From: Michel Normand <normand@linux.vnet.ibm.com>
Subject: mongodb_2_4_10_add_js_engine_v8_3_14_option.patch
Date: Wed, 04 Feb 2015 12:58:46 +0100

V8 3.14 scripting engine. Disabled by default. Enable using SCons flag js-engine=v8-3.14


This patch is similar to what was done in mongodb upstream:
for the commit 7e3f93197f73e5a2e0d1cff55c928dde102aa970
by Benety Goh <benety@mongodb.com>
SERVER-13686 V8 3.25 scripting engine. Disabled by default. Enable using SCons flag js-engine=v8-3.25

Signed-off-by: Michel Normand <normand@linux.vnet.ibm.com>

---
 SConstruct                               |   13 
 buildscripts/utils.py                    |    5 
 src/mongo/SConscript                     |   10 
 src/mongo/scripting/engine_v8-3.14.cpp   | 1738 +++++++++++++++++++++++++++++++
 src/mongo/scripting/engine_v8-3.14.h     |  560 +++++++++
 src/mongo/scripting/v8-3.14_db.cpp       |  981 +++++++++++++++++
 src/mongo/scripting/v8-3.14_db.h         |  122 ++
 src/mongo/scripting/v8-3.14_profiler.cpp |   65 +
 src/mongo/scripting/v8-3.14_profiler.h   |   46 
 src/mongo/scripting/v8-3.14_utils.cpp    |  255 ++++
 src/mongo/scripting/v8-3.14_utils.h      |  106 +
 src/third_party/SConscript               |    8 
 src/third_party/v8-3.14/SConscript       |  396 +++++++
 13 files changed, 4295 insertions(+), 10 deletions(-)

Index: mongodb-src-r2.4.10/SConstruct
===================================================================
--- mongodb-src-r2.4.10.orig/SConstruct
+++ mongodb-src-r2.4.10/SConstruct
@@ -173,7 +173,9 @@ add_option( "ssl" , "Enable SSL" , 0 , T
 
 # library choices
 add_option( "usesm" , "use spider monkey for javascript" , 0 , True )
-add_option( "usev8" , "use v8 for javascript" , 0 , True )
+js_engine_choices = ['v8-3.12', 'v8-3.14', 'none']
+add_option( "js-engine", "JavaScript scripting engine implementation", 1, True,
+           type='choice', default=js_engine_choices[0], choices=js_engine_choices)
 
 # mongo feature options
 add_option( "noshell", "don't build shell" , 0 , True )
@@ -276,7 +278,13 @@ debugLogging = has_option( "debugBuildAn
 noshell = has_option( "noshell" ) 
 
 usesm = has_option( "usesm" )
-usev8 = has_option( "usev8" ) 
+jsEngine = get_option( "js-engine")
+
+if ( not ( usesm ) ):
+    usev8 = (jsEngine != 'none')
+
+v8version = jsEngine[3:] if jsEngine.startswith('v8-') else 'none'
+v8suffix = '' if v8version == '3.12' else '-' + v8version
 
 asio = has_option( "asio" )
 
@@ -1136,6 +1144,7 @@ Export("testEnv")
 Export("has_option use_system_version_of_library")
 Export("installSetup")
 Export("usesm usev8")
+Export("v8version v8suffix")
 Export("darwin windows solaris linux freebsd nix")
 Export('module_sconscripts')
 Export("debugBuild")
Index: mongodb-src-r2.4.10/buildscripts/utils.py
===================================================================
--- mongodb-src-r2.4.10.orig/buildscripts/utils.py
+++ mongodb-src-r2.4.10/buildscripts/utils.py
@@ -24,6 +24,11 @@ def getAllSourceFiles( arr=None , prefix
     for x in os.listdir( prefix ):
         if x.startswith( "." ) or x.startswith( "pcre-" ) or x.startswith( "32bit" ) or x.startswith( "mongodb-" ) or x.startswith("debian") or x.startswith( "mongo-cxx-driver" ):
             continue
+        # XXX: Avoid conflict between v8 and v8-3.14 source files in
+        #      src/mongo/scripting
+        #      Remove after v8-3.14 migration.
+        if x.find("v8-3.14") != -1:
+            continue
         full = prefix + "/" + x
         if os.path.isdir( full ) and not os.path.islink( full ):
             getAllSourceFiles( arr , full )
Index: mongodb-src-r2.4.10/src/mongo/SConscript
===================================================================
--- mongodb-src-r2.4.10.orig/src/mongo/SConscript
+++ mongodb-src-r2.4.10/src/mongo/SConscript
@@ -11,6 +11,7 @@ Import("shellEnv")
 Import("testEnv")
 Import("has_option")
 Import("usesm usev8")
+Import("v8suffix")
 Import("installSetup")
 Import("enforce_glibc")
 Import("darwin windows solaris linux nix")
@@ -315,10 +316,11 @@ if usesm:
                                                              'scripting/sm_db.cpp'],
                       LIBDEPS=['$BUILD_DIR/third_party/js-1.7/js', 'bson_template_evaluator'])
 elif usev8:
-    env.StaticLibrary('scripting', scripting_common_files + ['scripting/engine_v8.cpp',
-                                                             'scripting/v8_db.cpp',
-                                                             'scripting/v8_utils.cpp',
-                                                             'scripting/v8_profiler.cpp'],
+    env.StaticLibrary('scripting', scripting_common_files + ['scripting/engine_v8' + v8suffix + '.cpp',
+                                                       'scripting/v8' + v8suffix + '_db.cpp',
+                                                       'scripting/v8' + v8suffix + '_utils.cpp',
+                                                       'scripting/v8' + v8suffix +
+                                                       '_profiler.cpp'],
                        LIBDEPS=['bson_template_evaluator', '$BUILD_DIR/third_party/shim_v8'])
 else:
     env.StaticLibrary('scripting', scripting_common_files + ['scripting/engine_none.cpp'],
Index: mongodb-src-r2.4.10/src/mongo/scripting/engine_v8-3.14.cpp
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/engine_v8-3.14.cpp
@@ -0,0 +1,1738 @@
+//engine_v8.cpp
+
+/*    Copyright 2009 10gen 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/>.
+ */
+
+#include "mongo/scripting/engine_v8-3.14.h"
+
+#include "mongo/platform/unordered_set.h"
+#include "mongo/scripting/v8-3.14_db.h"
+#include "mongo/scripting/v8-3.14_utils.h"
+#include "mongo/util/base64.h"
+#include "mongo/util/mongoutils/str.h"
+
+using namespace mongoutils;
+
+namespace mongo {
+
+    // Generated symbols for JS files
+    namespace JSFiles {
+        extern const JSFile types;
+        extern const JSFile assert;
+    }
+
+    // The  unwrapXXX functions extract internal fields from an object wrapped by wrapBSONObject.
+    // These functions are currently only used in places that should always have the correct
+    // type of object, however it may be possible for users to come up with a way to make these
+    // called with the wrong type so calling code should always check the returns.
+    static BSONHolder* unwrapHolder(V8Scope* scope, const v8::Handle<v8::Object>& obj) {
+        // Warning: can't throw exceptions in this context.
+        if (!scope->LazyBsonFT()->HasInstance(obj))
+            return NULL;
+
+        v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(obj->GetInternalField(0));
+        if (field.IsEmpty() || !field->IsExternal())
+            return 0;
+        void* ptr = field->Value();
+        return (BSONHolder*)ptr;
+    }
+
+    static BSONObj unwrapBSONObj(V8Scope* scope, const v8::Handle<v8::Object>& obj) {
+        // Warning: can't throw exceptions in this context.
+        BSONHolder* holder = unwrapHolder(scope, obj);
+        return holder ? holder->_obj : BSONObj();
+    }
+
+    static v8::Handle<v8::Object> unwrapObject(V8Scope* scope, const v8::Handle<v8::Object>& obj) {
+        // Warning: can't throw exceptions in this context.
+        if (!scope->LazyBsonFT()->HasInstance(obj))
+            return v8::Handle<v8::Object>();
+
+        return obj->GetInternalField(1).As<v8::Object>();
+    }
+
+    void V8Scope::wrapBSONObject(v8::Handle<v8::Object> obj, BSONObj data, bool readOnly) {
+        verify(LazyBsonFT()->HasInstance(obj));
+
+        // Nothing below throws
+        BSONHolder* holder = new BSONHolder(data);
+        holder->_readOnly = readOnly;
+        holder->_scope = this;
+        obj->SetInternalField(0, v8::External::New(holder)); // Holder
+        obj->SetInternalField(1, v8::Object::New()); // Object
+        v8::Persistent<v8::Object> p = v8::Persistent<v8::Object>::New(obj);
+        bsonHolderTracker.track(p, holder);
+    }
+
+    static v8::Handle<v8::Value> namedGet(v8::Local<v8::String> name,
+                                          const v8::AccessorInfo& info) {
+        v8::HandleScope handle_scope;
+        v8::Handle<v8::Value> val;
+        try {
+            V8Scope* scope = getScope(info.GetIsolate());
+            v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+            if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
+            if (realObject->HasOwnProperty(name)) {
+                // value already cached or added
+                return handle_scope.Close(realObject->Get(name));
+            }
+
+            string key = toSTLString(name);
+            BSONHolder* holder = unwrapHolder(scope, info.Holder());
+            if (!holder || holder->_removed.count(key))
+                return handle_scope.Close(v8::Handle<v8::Value>());
+
+            BSONObj obj = holder->_obj;
+            BSONElement elmt = obj.getField(key.c_str());
+            if (elmt.eoo())
+                return handle_scope.Close(v8::Handle<v8::Value>());
+
+            val = scope->mongoToV8Element(elmt, holder->_readOnly);
+
+            if (obj.objsize() > 128 || val->IsObject()) {
+                // Only cache if expected to help (large BSON) or is required due to js semantics
+                realObject->Set(name, val);
+            }
+
+            if (elmt.type() == mongo::Object || elmt.type() == mongo::Array) {
+              // if accessing a subobject, it may get modified and base obj would not know
+              // have to set base as modified, which means some optim is lost
+              holder->_modified = true;
+            }
+        }
+        catch (const DBException &dbEx) {
+            return v8AssertionException(dbEx.toString());
+        }
+        catch (...) {
+            return v8AssertionException(string("error getting property ") + toSTLString(name));
+        }
+        return handle_scope.Close(val);
+    }
+
+    static v8::Handle<v8::Value> namedGetRO(v8::Local<v8::String> name,
+                                            const v8::AccessorInfo &info) {
+        return namedGet(name, info);
+    }
+
+    static v8::Handle<v8::Value> namedSet(v8::Local<v8::String> name,
+                                          v8::Local<v8::Value> value_obj,
+                                          const v8::AccessorInfo& info) {
+        string key = toSTLString(name);
+        V8Scope* scope = getScope(info.GetIsolate());
+        BSONHolder* holder = unwrapHolder(scope, info.Holder());
+        if (!holder) return v8::Handle<v8::Value>();
+        holder->_removed.erase(key);
+        holder->_modified = true;
+
+        v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+        if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
+        realObject->Set(name, value_obj);
+        return value_obj;
+    }
+
+    static v8::Handle<v8::Array> namedEnumerator(const v8::AccessorInfo &info) {
+        v8::HandleScope handle_scope;
+        V8Scope* scope = getScope(info.GetIsolate());
+        BSONHolder* holder = unwrapHolder(scope, info.Holder());
+        if (!holder) return v8::Handle<v8::Array>();
+        BSONObj obj = holder->_obj;
+        v8::Handle<v8::Array> out = v8::Array::New();
+        int outIndex = 0;
+
+        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();
+            StringData sname (f.fieldName(), f.fieldNameSize()-1);
+            if (holder->_removed.count(sname.toString()))
+                continue;
+
+            v8::Handle<v8::String> name = scope->v8StringData(sname);
+            added.insert(sname);
+            out->Set(outIndex++, name);
+        }
+
+
+        v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+        if (realObject.IsEmpty()) return v8::Handle<v8::Array>();
+        v8::Handle<v8::Array> fields = realObject->GetOwnPropertyNames();
+        const int len = fields->Length();
+        for (int field=0; field < len; field++) {
+            v8::Handle<v8::String> name = fields->Get(field).As<v8::String>();
+            V8String sname (name);
+            if (added.count(sname))
+                continue;
+            out->Set(outIndex++, name);
+        }
+        return handle_scope.Close(out);
+    }
+
+    v8::Handle<v8::Boolean> namedDelete(v8::Local<v8::String> name, const v8::AccessorInfo& info) {
+        v8::HandleScope handle_scope;
+        string key = toSTLString(name);
+        V8Scope* scope = getScope(info.GetIsolate());
+        BSONHolder* holder = unwrapHolder(scope, info.Holder());
+        if (!holder) return v8::Handle<v8::Boolean>();
+        holder->_removed.insert(key);
+        holder->_modified = true;
+
+        v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+        if (realObject.IsEmpty()) return v8::Handle<v8::Boolean>();
+        realObject->Delete(name);
+        return v8::True();
+    }
+
+    static v8::Handle<v8::Value> indexedGet(uint32_t index, const v8::AccessorInfo &info) {
+        v8::HandleScope handle_scope;
+        v8::Handle<v8::Value> val;
+        try {
+            V8Scope* scope = getScope(info.GetIsolate());
+            v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+            if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
+            if (realObject->Has(index)) {
+                // value already cached or added
+                return handle_scope.Close(realObject->Get(index));
+            }
+            string key = str::stream() << index;
+
+            BSONHolder* holder = unwrapHolder(scope, info.Holder());
+            if (!holder) return v8::Handle<v8::Value>();
+            if (holder->_removed.count(key))
+                return handle_scope.Close(v8::Handle<v8::Value>());
+
+            BSONObj obj = holder->_obj;
+            BSONElement elmt = obj.getField(key);
+            if (elmt.eoo())
+                return handle_scope.Close(v8::Handle<v8::Value>());
+            val = scope->mongoToV8Element(elmt, holder->_readOnly);
+            realObject->Set(index, val);
+
+            if (elmt.type() == mongo::Object || elmt.type() == mongo::Array) {
+                // if accessing a subobject, it may get modified and base obj would not know
+                // have to set base as modified, which means some optim is lost
+                holder->_modified = true;
+            }
+        }
+        catch (const DBException &dbEx) {
+            return v8AssertionException(dbEx.toString());
+        }
+        catch (...) {
+            return v8AssertionException(str::stream() << "error getting indexed property "
+                                                      << index);
+        }
+        return handle_scope.Close(val);
+    }
+
+    v8::Handle<v8::Boolean> indexedDelete(uint32_t index, const v8::AccessorInfo& info) {
+        string key = str::stream() << index;
+        V8Scope* scope = getScope(info.GetIsolate());
+        BSONHolder* holder = unwrapHolder(scope, info.Holder());
+        if (!holder) return v8::Handle<v8::Boolean>();
+        holder->_removed.insert(key);
+        holder->_modified = true;
+
+        // also delete in JS obj
+        v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+        if (realObject.IsEmpty()) return v8::Handle<v8::Boolean>();
+        realObject->Delete(index);
+        return v8::True();
+    }
+
+    static v8::Handle<v8::Value> indexedGetRO(uint32_t index, const v8::AccessorInfo &info) {
+        return indexedGet(index, info);
+    }
+
+    static v8::Handle<v8::Value> indexedSet(uint32_t index, v8::Local<v8::Value> value_obj,
+                                            const v8::AccessorInfo& info) {
+        string key = str::stream() << index;
+        V8Scope* scope = getScope(info.GetIsolate());
+        BSONHolder* holder = unwrapHolder(scope, info.Holder());
+        if (!holder) return v8::Handle<v8::Value>();
+        holder->_removed.erase(key);
+        holder->_modified = true;
+
+        v8::Handle<v8::Object> realObject = unwrapObject(scope, info.Holder());
+        if (realObject.IsEmpty()) return v8::Handle<v8::Value>();
+        realObject->Set(index, value_obj);
+        return value_obj;
+    }
+
+    v8::Handle<v8::Value> NamedReadOnlySet(v8::Local<v8::String> property,
+                                           v8::Local<v8::Value> value,
+                                           const v8::AccessorInfo& info) {
+        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) {
+        cout << "cannot delete property " << V8String(property) << " from read-only object" << endl;
+        return v8::Boolean::New(false);
+    }
+
+    v8::Handle<v8::Value> IndexedReadOnlySet(uint32_t index, v8::Local<v8::Value> value,
+                                             const v8::AccessorInfo& info) {
+        cout << "cannot write property " << index << " to read-only array" << endl;
+        return value;
+    }
+
+    v8::Handle<v8::Boolean> IndexedReadOnlyDelete(uint32_t index, const v8::AccessorInfo& info) {
+        cout << "cannot delete property " << index << " from read-only array" << endl;
+        return v8::Boolean::New(false);
+    }
+
+    /**
+     * GC Prologue and Epilogue constants (used to display description constants)
+     */
+    struct GCPrologueState { static const char* name; };
+    const char* GCPrologueState::name = "prologue";
+    struct GCEpilogueState { static const char* name; };
+    const char* GCEpilogueState::name = "epilogue";
+
+    template <typename _GCState>
+    void gcCallback(v8::GCType type, v8::GCCallbackFlags flags) {
+        const int verbosity = 1;    // log level for stat collection
+        if (logLevel < verbosity)
+            // don't collect stats unless verbose
+            return;
+
+        v8::HeapStatistics stats;
+        v8::V8::GetHeapStatistics(&stats);
+        log() << "V8 GC " << _GCState::name
+              << " heap stats - "
+              << " total: " << stats.total_heap_size()
+              << " exec: " << stats.total_heap_size_executable()
+              << " used: " << stats.used_heap_size()<< " limit: "
+              << stats.heap_size_limit()
+              << endl;
+    }
+
+    V8ScriptEngine::V8ScriptEngine() :
+        _globalInterruptLock("GlobalV8InterruptLock"),
+        _opToScopeMap(),
+        _deadlineMonitor() {
+    }
+
+    V8ScriptEngine::~V8ScriptEngine() {
+    }
+
+    void ScriptEngine::setup() {
+        if (!globalScriptEngine) {
+            globalScriptEngine = new V8ScriptEngine();
+        }
+    }
+
+    std::string ScriptEngine::getInterpreterVersionString() {
+        return "V8 3.14.5";
+    }
+
+    void V8ScriptEngine::interrupt(unsigned opId) {
+        mongo::mutex::scoped_lock intLock(_globalInterruptLock);
+        OpIdToScopeMap::iterator iScope = _opToScopeMap.find(opId);
+        if (iScope == _opToScopeMap.end()) {
+            // got interrupt request for a scope that no longer exists
+            LOG(1) << "received interrupt request for unknown op: " << opId
+                   << printKnownOps_inlock() << endl;
+            return;
+        }
+        LOG(1) << "interrupting op: " << opId << printKnownOps_inlock() << endl;
+        iScope->second->kill();
+    }
+
+    void V8ScriptEngine::interruptAll() {
+        mongo::mutex::scoped_lock interruptLock(_globalInterruptLock);
+        for (OpIdToScopeMap::iterator iScope = _opToScopeMap.begin();
+             iScope != _opToScopeMap.end(); ++iScope) {
+            iScope->second->kill();
+        }
+    }
+
+    void V8Scope::registerOpId() {
+        scoped_lock giLock(_engine->_globalInterruptLock);
+        if (_engine->haveGetCurrentOpIdCallback()) {
+            // this scope has an associated operation
+            _opId = _engine->getCurrentOpId();
+            _engine->_opToScopeMap[_opId] = this;
+        }
+        else
+            // no associated op id (e.g. running from shell)
+            _opId = 0;
+        LOG(2) << "V8Scope " << this << " registered for op " << _opId << endl;
+    }
+
+    void V8Scope::unregisterOpId() {
+        scoped_lock giLock(_engine->_globalInterruptLock);
+        LOG(2) << "V8Scope " << this << " unregistered for op " << _opId << endl;
+        if (_engine->haveGetCurrentOpIdCallback() || _opId != 0) {
+            // scope is currently associated with an operation id
+            V8ScriptEngine::OpIdToScopeMap::iterator it = _engine->_opToScopeMap.find(_opId);
+            if (it != _engine->_opToScopeMap.end())
+                _engine->_opToScopeMap.erase(it);
+        }
+    }
+
+    bool V8Scope::nativePrologue() {
+        v8::Locker l(_isolate);
+        mongo::mutex::scoped_lock cbEnterLock(_interruptLock);
+        if (v8::V8::IsExecutionTerminating(_isolate)) {
+            LOG(2) << "v8 execution interrupted.  isolate: " << _isolate << endl;
+            return false;
+        }
+        if (_pendingKill || globalScriptEngine->interrupted()) {
+            // kill flag was set before entering our callback
+            LOG(2) << "marked for death while leaving callback.  isolate: " << _isolate << endl;
+            v8::V8::TerminateExecution(_isolate);
+            return false;
+        }
+        _inNativeExecution = true;
+        return true;
+    }
+
+    bool V8Scope::nativeEpilogue() {
+        v8::Locker l(_isolate);
+        mongo::mutex::scoped_lock cbLeaveLock(_interruptLock);
+        _inNativeExecution = false;
+        if (v8::V8::IsExecutionTerminating(_isolate)) {
+            LOG(2) << "v8 execution interrupted.  isolate: " << _isolate << endl;
+            return false;
+        }
+        if (_pendingKill || globalScriptEngine->interrupted()) {
+            LOG(2) << "marked for death while leaving callback.  isolate: " << _isolate << endl;
+            v8::V8::TerminateExecution(_isolate);
+            return false;
+        }
+        return true;
+    }
+
+    void V8Scope::kill() {
+        mongo::mutex::scoped_lock interruptLock(_interruptLock);
+        if (!_inNativeExecution) {
+            // Set the TERMINATE flag on the stack guard for this isolate.
+            // This won't happen between calls to nativePrologue and nativeEpilogue().
+            v8::V8::TerminateExecution(_isolate);
+            LOG(1) << "killing v8 scope.  isolate: " << _isolate << endl;
+        }
+        LOG(1) << "marking v8 scope for death.  isolate: " << _isolate << endl;
+        _pendingKill = true;
+    }
+
+    /** check if there is a pending killOp request */
+    bool V8Scope::isKillPending() const {
+        return _pendingKill || _engine->interrupted();
+    }
+
+    /**
+     * Display a list of all known ops (for verbose output)
+     */
+    std::string V8ScriptEngine::printKnownOps_inlock() {
+        stringstream out;
+        if (logLevel > 1) {
+            out << "  known ops: " << endl;
+            for(OpIdToScopeMap::iterator iSc = _opToScopeMap.begin();
+                iSc != _opToScopeMap.end(); ++iSc) {
+                out << "  " << iSc->first << endl;
+            }
+        }
+        return out.str();
+    }
+
+
+    V8Scope::V8Scope(V8ScriptEngine * engine)
+        : _engine(engine),
+          _connectState(NOT),
+          _cpuProfiler(),
+          _interruptLock("ScopeInterruptLock"),
+          _inNativeExecution(true),
+          _pendingKill(false) {
+
+        // create new isolate and enter it via a scope
+        _isolate = v8::Isolate::New();
+        v8::Isolate::Scope iscope(_isolate);
+
+        // lock the isolate and enter the context
+        v8::Locker l(_isolate);
+        v8::HandleScope handleScope;
+        _context = v8::Context::New();
+        v8::Context::Scope context_scope(_context);
+
+        _isolate->SetData(this);
+
+        // display heap statistics on MarkAndSweep GC run
+        v8::V8::AddGCPrologueCallback(gcCallback<GCPrologueState>, v8::kGCTypeMarkSweepCompact);
+        v8::V8::AddGCEpilogueCallback(gcCallback<GCEpilogueState>, v8::kGCTypeMarkSweepCompact);
+
+        // if the isolate runs out of heap space, raise a flag on the StackGuard instead of
+        // calling abort()
+        v8::V8::IgnoreOutOfMemoryException();
+
+        // create a global (rooted) object
+        _global = v8::Persistent<v8::Object>::New(_context->Global());
+
+        // Grab the RegExp constructor before user code gets a chance to change it. This ensures
+        // we can always construct proper RegExps from C++.
+        v8::Handle<v8::Value> regexp = _global->Get(strLitToV8("RegExp"));
+        verify(regexp->IsFunction());
+        _jsRegExpConstructor = v8::Persistent<v8::Function>::New(regexp.As<v8::Function>());
+
+        // initialize lazy object template
+        _LazyBsonFT = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+        LazyBsonFT()->InstanceTemplate()->SetInternalFieldCount(2);
+        LazyBsonFT()->InstanceTemplate()->SetNamedPropertyHandler(
+                namedGet, namedSet, NULL, namedDelete, namedEnumerator);
+        LazyBsonFT()->InstanceTemplate()->SetIndexedPropertyHandler(
+                indexedGet, indexedSet, NULL, indexedDelete, namedEnumerator);
+        LazyBsonFT()->PrototypeTemplate()->Set(strLitToV8("_bson"),
+                                               v8::Boolean::New(true),
+                                               v8::DontEnum);
+
+        _ROBsonFT = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
+        ROBsonFT()->Inherit(LazyBsonFT()); // This makes LazyBsonFT()->HasInstance() true
+        ROBsonFT()->InstanceTemplate()->SetInternalFieldCount(2);
+        ROBsonFT()->InstanceTemplate()->SetNamedPropertyHandler(
+                namedGetRO, NamedReadOnlySet, NULL, NamedReadOnlyDelete, namedEnumerator);
+        ROBsonFT()->InstanceTemplate()->SetIndexedPropertyHandler(
+                indexedGetRO, IndexedReadOnlySet, NULL, IndexedReadOnlyDelete, NULL);
+        ROBsonFT()->PrototypeTemplate()->Set(strLitToV8("_bson"),
+                                             v8::Boolean::New(true),
+                                             v8::DontEnum);
+
+        injectV8Function("print", Print);
+        injectV8Function("version", Version);  // TODO: remove
+        injectV8Function("gc", GCV8);
+        // injectV8Function("startCpuProfiler", startCpuProfiler);
+        // injectV8Function("stopCpuProfiler", stopCpuProfiler);
+        // injectV8Function("getCpuProfile", getCpuProfile);
+
+        // install BSON functions in the global object
+        installBSONTypes();
+
+        // load JS helpers (dependancy: installBSONTypes)
+        execSetup(JSFiles::assert);
+        execSetup(JSFiles::types);
+
+        // install process-specific utilities in the global scope (dependancy: types.js, assert.js)
+        if (_engine->_scopeInitCallback)
+            _engine->_scopeInitCallback(*this);
+
+        // install global utility functions
+        installGlobalUtils(*this);
+
+        registerOpId();
+    }
+
+    V8Scope::~V8Scope() {
+        unregisterOpId();
+        {
+            V8_SIMPLE_HEADER
+            for(unsigned i = 0; i < _funcs.size(); ++i)
+                _funcs[ i ].Dispose();
+            _funcs.clear();
+            _global.Dispose();
+            _context.Dispose();
+            // Note: This block is unnecessary since we destroy the v8 Heap (Isolate) immediately
+            //       after. Leaving in for now, but nothing new should be added.
+        }
+        _isolate->Dispose();
+        // set the isolate to NULL so ObjTracker destructors know that v8 is no longer reachable
+        _isolate = NULL;
+    }
+
+    bool V8Scope::hasOutOfMemoryException() {
+        V8_SIMPLE_HEADER
+        if (!_context.IsEmpty())
+            return _context->HasOutOfMemoryException();
+        return false;
+    }
+
+    v8::Handle<v8::Value> V8Scope::load(V8Scope* scope, const v8::Arguments &args) {
+        v8::Context::Scope context_scope(scope->_context);
+        for (int i = 0; i < args.Length(); ++i) {
+            std::string filename(toSTLString(args[i]));
+            if (!scope->execFile(filename, false, true, false)) {
+                return v8AssertionException(string("error loading js file: ") + filename);
+            }
+        }
+        return v8::True();
+    }
+
+    v8::Handle<v8::Value> V8Scope::nativeCallback(V8Scope* scope, const v8::Arguments &args) {
+        BSONObj ret;
+        string exceptionText;
+        v8::HandleScope handle_scope;
+        try {
+            v8::Local<v8::External> f =
+                    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(scope->strLitToV8("_native_data")));
+            BSONObjBuilder b;
+            for (int i = 0; i < args.Length(); ++i)
+                scope->v8ToMongoElement(b, BSONObjBuilder::numStr(i), args[i]);
+            BSONObj nativeArgs = b.obj();
+            ret = function(nativeArgs, data->Value());
+        }
+        catch (const std::exception &e) {
+            exceptionText = e.what();
+        }
+        catch (...) {
+            exceptionText = "unknown exception in V8Scope::nativeCallback";
+        }
+        if (!exceptionText.empty()) {
+            return v8AssertionException(exceptionText);
+        }
+        return handle_scope.Close(scope->mongoToV8Element(ret.firstElement()));
+    }
+
+    v8::Handle<v8::Value> V8Scope::v8Callback(const v8::Arguments &args) {
+        v8::HandleScope handle_scope;
+        V8Scope* scope = getScope(args.GetIsolate());
+
+        if (!scope->nativePrologue())
+            // execution terminated
+            return v8::Undefined();
+
+        v8::Local<v8::External> f =
+                v8::External::Cast(*args.Callee()->Get(scope->strLitToV8("_v8_function")));
+        v8Function function = (v8Function)(f->Value());
+        v8::Handle<v8::Value> ret;
+        string exceptionText;
+
+        try {
+            // execute the native function
+            ret = function(scope, args);
+        }
+        catch (const std::exception& e) {
+            exceptionText = e.what();
+        }
+        catch (...) {
+            exceptionText = "unknown exception in V8Scope::v8Callback";
+        }
+
+        if (!scope->nativeEpilogue())
+            // execution terminated
+            return v8::Undefined();
+
+        if (!exceptionText.empty()) {
+            return v8AssertionException(exceptionText);
+        }
+        return handle_scope.Close(ret);
+    }
+
+    void V8Scope::init(const BSONObj * data) {
+        if (! data)
+            return;
+
+        BSONObjIterator i(*data);
+        while (i.more()) {
+            BSONElement e = i.next();
+            setElement(e.fieldName(), e);
+        }
+    }
+
+    void V8Scope::setNumber(const char * field, double val) {
+        V8_SIMPLE_HEADER
+        _global->ForceSet(v8StringData(field), v8::Number::New(val));
+    }
+
+    void V8Scope::setString(const char * field, const char * val) {
+        V8_SIMPLE_HEADER
+        _global->ForceSet(v8StringData(field), v8::String::New(val));
+    }
+
+    void V8Scope::setBoolean(const char * field, bool val) {
+        V8_SIMPLE_HEADER
+        _global->ForceSet(v8StringData(field), v8::Boolean::New(val));
+    }
+
+    void V8Scope::setElement(const char *field, const BSONElement& e) {
+        V8_SIMPLE_HEADER
+        _global->ForceSet(v8StringData(field), mongoToV8Element(e));
+    }
+
+    void V8Scope::setObject(const char *field, const BSONObj& obj, bool readOnly) {
+        V8_SIMPLE_HEADER
+        _global->ForceSet(v8StringData(field),
+                          mongoToLZV8(obj, readOnly ? v8::ReadOnly : v8::None));
+    }
+
+    int V8Scope::type(const char *field) {
+        V8_SIMPLE_HEADER
+        v8::Handle<v8::Value> v = get(field);
+        if (v->IsNull())
+            return jstNULL;
+        if (v->IsUndefined())
+            return Undefined;
+        if (v->IsString())
+            return String;
+        if (v->IsFunction())
+            return Code;
+        if (v->IsArray())
+            return Array;
+        if (v->IsBoolean())
+            return Bool;
+        // needs to be explicit NumberInt to use integer
+//        if (v->IsInt32())
+//            return NumberInt;
+        if (v->IsNumber())
+            return NumberDouble;
+        if (v->IsExternal()) {
+            uassert(10230,  "can't handle external yet", 0);
+            return -1;
+        }
+        if (v->IsDate())
+            return Date;
+        if (v->IsObject())
+            return Object;
+
+        uasserted(12509, str::stream() << "unable to get type of field " << field);
+    }
+
+    v8::Handle<v8::Value> V8Scope::get(const char * field) {
+        return _global->Get(v8StringData(field));
+    }
+
+    double V8Scope::getNumber(const char *field) {
+        V8_SIMPLE_HEADER
+        return get(field)->ToNumber()->Value();
+    }
+
+    int V8Scope::getNumberInt(const char *field) {
+        V8_SIMPLE_HEADER
+        return get(field)->ToInt32()->Value();
+    }
+
+    long long V8Scope::getNumberLongLong(const char *field) {
+        V8_SIMPLE_HEADER
+        return get(field)->ToInteger()->Value();
+    }
+
+    string V8Scope::getString(const char *field) {
+        V8_SIMPLE_HEADER
+        return toSTLString(get(field));
+    }
+
+    bool V8Scope::getBoolean(const char *field) {
+        V8_SIMPLE_HEADER
+        return get(field)->ToBoolean()->Value();
+    }
+
+    BSONObj V8Scope::getObject(const char * field) {
+        V8_SIMPLE_HEADER
+        v8::Handle<v8::Value> v = get(field);
+        if (v->IsNull() || v->IsUndefined())
+            return BSONObj();
+        uassert(10231,  "not an object", v->IsObject());
+        return v8ToMongo(v->ToObject());
+    }
+
+    v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate(V8Scope* scope) {
+        v8::Handle<v8::FunctionTemplate> numberLong = scope->createV8Function(numberLongInit);
+        v8::Handle<v8::ObjectTemplate> proto = numberLong->PrototypeTemplate();
+        scope->injectV8Method("valueOf", numberLongValueOf, proto);
+        scope->injectV8Method("toNumber", numberLongToNumber, proto);
+        scope->injectV8Method("toString", numberLongToString, proto);
+        return numberLong;
+    }
+
+    v8::Handle<v8::FunctionTemplate> getNumberIntFunctionTemplate(V8Scope* scope) {
+        v8::Handle<v8::FunctionTemplate> numberInt = scope->createV8Function(numberIntInit);
+        v8::Handle<v8::ObjectTemplate> proto = numberInt->PrototypeTemplate();
+        scope->injectV8Method("valueOf", numberIntValueOf, proto);
+        scope->injectV8Method("toNumber", numberIntToNumber, proto);
+        scope->injectV8Method("toString", numberIntToString, proto);
+        return numberInt;
+    }
+
+    v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate(V8Scope* scope) {
+        v8::Handle<v8::FunctionTemplate> binData = scope->createV8Function(binDataInit);
+        binData->InstanceTemplate()->SetInternalFieldCount(1);
+        v8::Handle<v8::ObjectTemplate> proto = binData->PrototypeTemplate();
+        scope->injectV8Method("toString", binDataToString, proto);
+        scope->injectV8Method("base64", binDataToBase64, proto);
+        scope->injectV8Method("hex", binDataToHex, proto);
+        return binData;
+    }
+
+    v8::Handle<v8::FunctionTemplate> getTimestampFunctionTemplate(V8Scope* scope) {
+        v8::Handle<v8::FunctionTemplate> ts = scope->createV8Function(dbTimestampInit);
+        return ts;
+    }
+
+    v8::Handle<v8::Value> minKeyToJson(V8Scope* scope, const v8::Arguments& args) {
+        // MinKey can't just be an object like {$minKey:1} since insert() checks for fields that
+        // start with $ and raises an error. See DBCollection.prototype._validateForStorage().
+        return scope->strLitToV8("{ \"$minKey\" : 1 }");
+    }
+
+    v8::Handle<v8::Value> minKeyCall(const v8::Arguments& args) {
+        // The idea here is that MinKey and MaxKey are singleton callable objects
+        // that return the singleton when called. This enables all instances to
+        // compare == and === to MinKey even if created by "new MinKey()" in JS.
+        V8Scope* scope = getScope(args.GetIsolate());
+
+        v8::Handle<v8::Function> func = scope->MinKeyFT()->GetFunction();
+        v8::Handle<v8::String> name = scope->strLitToV8("singleton");
+        v8::Handle<v8::Value> singleton = func->GetHiddenValue(name);
+        if (!singleton.IsEmpty())
+            return singleton;
+
+        if (!args.IsConstructCall())
+            return func->NewInstance();
+
+        verify(scope->MinKeyFT()->HasInstance(args.This()));
+
+        func->SetHiddenValue(name, args.This());
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::FunctionTemplate> getMinKeyFunctionTemplate(V8Scope* scope) {
+        v8::Handle<v8::FunctionTemplate> myTemplate = v8::FunctionTemplate::New(minKeyCall);
+        myTemplate->InstanceTemplate()->SetCallAsFunctionHandler(minKeyCall);
+        myTemplate->PrototypeTemplate()->Set(
+                "tojson", scope->createV8Function(minKeyToJson)->GetFunction());
+        myTemplate->SetClassName(scope->strLitToV8("MinKey"));
+        return myTemplate;
+    }
+
+    v8::Handle<v8::Value> maxKeyToJson(V8Scope* scope, const v8::Arguments& args) {
+        return scope->strLitToV8("{ \"$maxKey\" : 1 }");
+    }
+
+    v8::Handle<v8::Value> maxKeyCall(const v8::Arguments& args) {
+        // See comment in minKeyCall.
+        V8Scope* scope = getScope(args.GetIsolate());
+
+        v8::Handle<v8::Function> func = scope->MaxKeyFT()->GetFunction();
+        v8::Handle<v8::String> name = scope->strLitToV8("singleton");
+        v8::Handle<v8::Value> singleton = func->GetHiddenValue(name);
+        if (!singleton.IsEmpty())
+            return singleton;
+
+        if (!args.IsConstructCall())
+            return func->NewInstance();
+
+        verify(scope->MaxKeyFT()->HasInstance(args.This()));
+
+        func->SetHiddenValue(name, args.This());
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::FunctionTemplate> getMaxKeyFunctionTemplate(V8Scope* scope) {
+        v8::Handle<v8::FunctionTemplate> myTemplate = v8::FunctionTemplate::New(maxKeyCall);
+        myTemplate->InstanceTemplate()->SetCallAsFunctionHandler(maxKeyCall);
+        myTemplate->PrototypeTemplate()->Set(
+                "tojson", scope->createV8Function(maxKeyToJson)->GetFunction());
+        myTemplate->SetClassName(scope->strLitToV8("MaxKey"));
+        return myTemplate;
+    }
+
+    std::string V8Scope::v8ExceptionToSTLString(const v8::TryCatch* try_catch) {
+        stringstream ss;
+        v8::String::Utf8Value exceptionText(try_catch->Exception());
+        ss << *exceptionText;
+
+        // get the exception message
+        v8::Handle<v8::Message> message = try_catch->Message();
+        if (message.IsEmpty())
+            return ss.str();
+
+        // get the resource (e.g. file or internal call)
+        v8::String::Utf8Value resourceName(message->GetScriptResourceName());
+        if (!*resourceName)
+            return ss.str();
+
+        string resourceNameString = *resourceName;
+        if (resourceNameString.compare("undefined") == 0)
+            return ss.str();
+        if (resourceNameString.find("_funcs") == 0) {
+            // script loaded from __createFunction
+            string code;
+            // find the source script based on the resource name supplied to v8::Script::Compile().
+            // this is accomplished by converting the integer after the '_funcs' prefix.
+            unsigned int funcNum = str::toUnsigned(resourceNameString.substr(6));
+            for (map<string, ScriptingFunction>::iterator it = getFunctionCache().begin();
+                 it != getFunctionCache().end();
+                 ++it) {
+                if (it->second == funcNum) {
+                    code = it->first;
+                    break;
+                }
+            }
+            if (!code.empty()) {
+                // append surrounding code (padded with up to 20 characters on each side)
+                int startPos = message->GetStartPosition();
+                const int kPadding = 20;
+                if (startPos - kPadding < 0)
+                    // lower bound exceeded
+                    startPos = 0;
+                else
+                    startPos -= kPadding;
+
+                int displayRange = message->GetEndPosition();
+                if (displayRange + kPadding > static_cast<int>(code.length()))
+                    // upper bound exceeded
+                    displayRange -= startPos;
+                else
+                    // compensate for startPos padding
+                    displayRange = (displayRange - startPos) + kPadding;
+
+                if (startPos > static_cast<int>(code.length()) ||
+                    displayRange > static_cast<int>(code.length()))
+                    return ss.str();
+
+                string codeNear = code.substr(startPos, displayRange);
+                for (size_t newLine = codeNear.find('\n');
+                     newLine != string::npos;
+                     newLine = codeNear.find('\n')) {
+                    if (static_cast<int>(newLine) > displayRange - kPadding) {
+                        // truncate at first newline past the reported end position
+                        codeNear = codeNear.substr(0, newLine - 1);
+                        break;
+                    }
+                    // convert newlines to spaces
+                    codeNear.replace(newLine, 1, " ");
+                }
+                // trim leading chars
+                codeNear = str::ltrim(codeNear);
+                ss << " near '" << codeNear << "' ";
+                const int linenum = message->GetLineNumber();
+                if (linenum != 1)
+                    ss << " (line " << linenum << ")";
+            }
+        }
+        else if (resourceNameString.find("(shell") == 0) {
+            // script loaded from shell input -- simply print the error
+        }
+        else {
+            // script loaded from file
+            ss << " at " << *resourceName;
+            const int linenum = message->GetLineNumber();
+            if (linenum != 1) ss << ":" << linenum;
+        }
+        return ss.str();
+    }
+
+    // --- functions -----
+
+    bool hasFunctionIdentifier(const StringData& code) {
+        if (code.size() < 9 || code.find("function") != 0 )
+            return false;
+
+        return code[8] == ' ' || code[8] == '(';
+    }
+
+    v8::Local<v8::Function> V8Scope::__createFunction(const char* raw,
+                                                      ScriptingFunction functionNumber) {
+        v8::HandleScope handle_scope;
+        v8::TryCatch try_catch;
+        raw = jsSkipWhiteSpace(raw);
+        string code = raw;
+        if (!hasFunctionIdentifier(code)) {
+            if (code.find('\n') == string::npos &&
+                    ! hasJSReturn(code) &&
+                    (code.find(';') == string::npos || code.find(';') == code.size() - 1)) {
+                code = "return " + code;
+            }
+            code = "function(){ " + code + "}";
+        }
+
+        string fn = str::stream() << "_funcs" << functionNumber;
+        code = str::stream() << fn << " = " << code;
+
+        v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(code.c_str()),
+                                        v8::String::New(fn.c_str()));
+
+        // throw on error
+        checkV8ErrorState(script, try_catch);
+
+        v8::Local<v8::Value> result = script->Run();
+
+        // throw on error
+        checkV8ErrorState(result, try_catch);
+
+        return handle_scope.Close(v8::Handle<v8::Function>(
+                v8::Function::Cast(*_global->Get(v8::String::New(fn.c_str())))));
+    }
+
+    ScriptingFunction V8Scope::_createFunction(const char* raw, ScriptingFunction functionNumber) {
+        V8_SIMPLE_HEADER
+        v8::Local<v8::Value> ret = __createFunction(raw, functionNumber);
+        v8::Persistent<v8::Value> f = v8::Persistent<v8::Value>::New(ret);
+        uassert(10232, "not a function", f->IsFunction());
+        _funcs.push_back(f);
+        return functionNumber;
+    }
+
+    void V8Scope::setFunction(const char* field, const char* code) {
+        V8_SIMPLE_HEADER
+        _global->ForceSet(v8StringData(field),
+                          __createFunction(code, getFunctionCache().size() + 1));
+    }
+
+    void V8Scope::rename(const char * from, const char * to) {
+        V8_SIMPLE_HEADER;
+        v8::Handle<v8::String> f = v8StringData(from);
+        v8::Handle<v8::String> t = v8StringData(to);
+        _global->ForceSet(t, _global->Get(f));
+        _global->ForceSet(f, v8::Undefined());
+    }
+
+    int V8Scope::invoke(ScriptingFunction func, const BSONObj* argsObject, const BSONObj* recv,
+                        int timeoutMs, bool ignoreReturn, bool readOnlyArgs, bool readOnlyRecv) {
+        V8_SIMPLE_HEADER
+        v8::Handle<v8::Value> funcValue = _funcs[func-1];
+        v8::TryCatch try_catch;
+        v8::Local<v8::Value> result;
+
+        // TODO SERVER-8016: properly allocate handles on the stack
+        static const int MAX_ARGS = 24;
+        const int nargs = argsObject ? argsObject->nFields() : 0;
+        uassert(16862, "Too many arguments. Max is 24",
+                nargs <= MAX_ARGS);
+
+        v8::Handle<v8::Value> args[MAX_ARGS];
+        if (nargs) {
+            BSONObjIterator it(*argsObject);
+            for (int i=0; i<nargs; i++) {
+                BSONElement next = it.next();
+                args[i] = mongoToV8Element(next, readOnlyArgs);
+            }
+        }
+
+        v8::Handle<v8::Object> v8recv;
+        if (recv != 0)
+            v8recv = mongoToLZV8(*recv, readOnlyRecv);
+        else
+            v8recv = _global;
+
+        if (!nativeEpilogue()) {
+            _error = "JavaScript execution terminated";
+            log() << _error << endl;
+            uasserted(16711, _error);
+        }
+
+        if (timeoutMs)
+            // start the deadline timer for this script
+            _engine->getDeadlineMonitor()->startDeadline(this, timeoutMs);
+
+        result = ((v8::Function*)(*funcValue))->Call(v8recv, nargs, nargs ? args : NULL);
+
+        if (timeoutMs)
+            // stop the deadline timer for this script
+            _engine->getDeadlineMonitor()->stopDeadline(this);
+
+        if (!nativePrologue()) {
+            _error = "JavaScript execution terminated";
+            log() << _error << endl;
+            uasserted(16712, _error);
+        }
+
+        // throw on error
+        checkV8ErrorState(result, try_catch);
+
+        if (!ignoreReturn) {
+            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(strLitToV8("_v8_function"))) {
+                log() << "storing native function as return value" << endl;
+                _lastRetIsNativeCode = true;
+            }
+            else {
+                _lastRetIsNativeCode = false;
+            }
+            _global->ForceSet(strLitToV8("__returnValue"), result);
+        }
+
+        return 0;
+    }
+
+    bool V8Scope::exec(const StringData& code, const string& name, bool printResult,
+                       bool reportError, bool assertOnError, int timeoutMs) {
+        V8_SIMPLE_HEADER
+        v8::TryCatch try_catch;
+
+        v8::Handle<v8::Script> script =
+                v8::Script::Compile(v8::String::New(code.rawData(), code.size()),
+                                    v8::String::New(name.c_str()));
+
+        if (checkV8ErrorState(script, try_catch, reportError, assertOnError))
+            return false;
+
+        if (!nativeEpilogue()) {
+            _error = "JavaScript execution terminated";
+            if (reportError)
+                log() << _error << endl;
+            if (assertOnError)
+                uasserted(13475, _error);
+            return false;
+        }
+
+        if (timeoutMs)
+            // start the deadline timer for this script
+            _engine->getDeadlineMonitor()->startDeadline(this, timeoutMs);
+
+        v8::Handle<v8::Value> result = script->Run();
+
+        if (timeoutMs)
+            // stopt the deadline timer for this script
+            _engine->getDeadlineMonitor()->stopDeadline(this);
+
+        if (!nativePrologue()) {
+            _error = "JavaScript execution terminated";
+            if (reportError)
+                log() << _error << endl;
+            if (assertOnError)
+                uasserted(16721, _error);
+            return false;
+        }
+
+        if (checkV8ErrorState(result, try_catch, reportError, assertOnError))
+            return false;
+
+        _global->ForceSet(strLitToV8("__lastres__"), result);
+
+        if (printResult && !result->IsUndefined()) {
+            // appears to only be used by shell
+            cout << V8String(result) << endl;
+        }
+
+        return true;
+    }
+
+    void V8Scope::injectNative(const char *field, NativeFunction func, void* data) {
+        V8_SIMPLE_HEADER    // required due to public access
+        injectNative(field, func, _global, data);
+    }
+
+    void V8Scope::injectNative(const char *field, NativeFunction func, v8::Handle<v8::Object>& obj,
+                               void* data) {
+        v8::Handle<v8::FunctionTemplate> ft = createV8Function(nativeCallback);
+        ft->Set(strLitToV8("_native_function"),
+                           v8::External::New((void*)func),
+                           v8::PropertyAttribute(v8::DontEnum | v8::ReadOnly));
+        ft->Set(strLitToV8("_native_data"),
+                           v8::External::New(data),
+                           v8::PropertyAttribute(v8::DontEnum | v8::ReadOnly));
+        injectV8Function(field, ft, obj);
+    }
+
+    v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Function(const char *field, v8Function func) {
+        return injectV8Function(field, func, _global);
+    }
+
+    v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Function(const char *field,
+                                                               v8Function func,
+                                                               v8::Handle<v8::Object>& obj) {
+        return injectV8Function(field, createV8Function(func), obj);
+    }
+
+    v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Function(const char *fieldCStr,
+                                                               v8::Handle<v8::FunctionTemplate> ft,
+                                                               v8::Handle<v8::Object>& obj) {
+        v8::Handle<v8::String> field = v8StringData(fieldCStr);
+        ft->SetClassName(field);
+        v8::Handle<v8::Function> func = ft->GetFunction();
+        func->SetName(field);
+        obj->ForceSet(field, func);
+        return ft;
+    }
+
+    v8::Handle<v8::FunctionTemplate> V8Scope::injectV8Method(
+            const char *fieldCStr,
+            v8Function func,
+            v8::Handle<v8::ObjectTemplate>& proto) {
+        v8::Handle<v8::String> field = v8StringData(fieldCStr);
+        v8::Handle<v8::FunctionTemplate> ft = createV8Function(func);
+        v8::Handle<v8::Function> f = ft->GetFunction();
+        f->SetName(field);
+        proto->Set(field, f);
+        return ft;
+    }
+
+    v8::Handle<v8::FunctionTemplate> V8Scope::createV8Function(v8Function func) {
+        v8::Handle<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(v8Callback);
+        ft->Set(strLitToV8("_v8_function"), v8::External::New(reinterpret_cast<void*>(func)),
+                static_cast<v8::PropertyAttribute>(v8::DontEnum | v8::ReadOnly));
+        return ft;
+    }
+
+    void V8Scope::gc() {
+        V8_SIMPLE_HEADER
+        // trigger low memory notification.  for more granular control over garbage
+        // collection cycle, @see v8::V8::IdleNotification.
+        v8::V8::LowMemoryNotification();
+    }
+
+    void V8Scope::localConnect(const char * dbName) {
+        typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
+        {
+            V8_SIMPLE_HEADER
+            if (_connectState == EXTERNAL)
+                uasserted(12510, "externalSetup already called, can't call localConnect");
+            if (_connectState ==  LOCAL) {
+                if (_localDBName == dbName)
+                    return;
+                uasserted(12511,
+                          str::stream() << "localConnect previously called with name "
+                                        << _localDBName);
+            }
+
+            // NOTE: order is important here.  the following methods must be called after
+            //       the above conditional statements.
+
+            // install db access functions in the global object
+            installDBAccess();
+
+            // add global load() helper
+            injectV8Function("load", load);
+
+            // install the Mongo function object and instantiate the 'db' global
+            _MongoFT = FTPtr::New(getMongoFunctionTemplate(this, true));
+            injectV8Function("Mongo", MongoFT(), _global);
+            execCoreFiles();
+            exec("_mongo = new Mongo();", "local connect 2", false, true, true, 0);
+            exec((string)"db = _mongo.getDB(\"" + dbName + "\");", "local connect 3",
+                 false, true, true, 0);
+            _connectState = LOCAL;
+            _localDBName = dbName;
+        }
+        loadStored();
+    }
+
+    void V8Scope::externalSetup() {
+        typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
+        V8_SIMPLE_HEADER
+        if (_connectState == EXTERNAL)
+            return;
+        if (_connectState == LOCAL)
+            uasserted(12512, "localConnect already called, can't call externalSetup");
+
+        // install db access functions in the global object
+        installDBAccess();
+
+        // install thread-related functions (e.g. _threadInject)
+        installFork(this, _global, _context);
+
+        // install 'load' helper function
+        injectV8Function("load", load);
+
+        // install the Mongo function object
+        _MongoFT = FTPtr::New(getMongoFunctionTemplate(this, false));
+        injectV8Function("Mongo", MongoFT(), _global);
+        execCoreFiles();
+        _connectState = EXTERNAL;
+    }
+
+    void V8Scope::installDBAccess() {
+        typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
+        _DBFT             = FTPtr::New(createV8Function(dbInit));
+        _DBQueryFT        = FTPtr::New(createV8Function(dbQueryInit));
+        _DBCollectionFT   = FTPtr::New(createV8Function(collectionInit));
+
+        // These must be done before calling injectV8Function
+        DBFT()->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter, collectionSetter);
+        DBQueryFT()->InstanceTemplate()->SetIndexedPropertyHandler(dbQueryIndexAccess);
+        DBCollectionFT()->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter,
+                                                                      collectionSetter);
+
+        injectV8Function("DB", DBFT(), _global);
+        injectV8Function("DBQuery", DBQueryFT(), _global);
+        injectV8Function("DBCollection", DBCollectionFT(), _global);
+
+        // The internal cursor type isn't exposed to the users at all
+        _InternalCursorFT = FTPtr::New(getInternalCursorFunctionTemplate(this));
+    }
+
+    void V8Scope::installBSONTypes() {
+        typedef v8::Persistent<v8::FunctionTemplate> FTPtr;
+        _ObjectIdFT  = FTPtr::New(injectV8Function("ObjectId", objectIdInit));
+        _DBRefFT     = FTPtr::New(injectV8Function("DBRef", dbRefInit));
+        _DBPointerFT = FTPtr::New(injectV8Function("DBPointer", dbPointerInit));
+
+        _BinDataFT    = FTPtr::New(getBinDataFunctionTemplate(this));
+        _NumberLongFT = FTPtr::New(getNumberLongFunctionTemplate(this));
+        _NumberIntFT  = FTPtr::New(getNumberIntFunctionTemplate(this));
+        _TimestampFT  = FTPtr::New(getTimestampFunctionTemplate(this));
+        _MinKeyFT     = FTPtr::New(getMinKeyFunctionTemplate(this));
+        _MaxKeyFT     = FTPtr::New(getMaxKeyFunctionTemplate(this));
+
+        injectV8Function("BinData", BinDataFT(), _global);
+        injectV8Function("NumberLong", NumberLongFT(), _global);
+        injectV8Function("NumberInt", NumberIntFT(), _global);
+        injectV8Function("Timestamp", TimestampFT(), _global);
+
+        // These are instances created from the functions, not the functions themselves
+        _global->ForceSet(strLitToV8("MinKey"), MinKeyFT()->GetFunction()->NewInstance());
+        _global->ForceSet(strLitToV8("MaxKey"), MaxKeyFT()->GetFunction()->NewInstance());
+
+        // These all create BinData objects so we don't need to hold on to them.
+        injectV8Function("UUID", uuidInit);
+        injectV8Function("MD5", md5Init);
+        injectV8Function("HexData", hexDataInit);
+
+        _global->Get(strLitToV8("Object"))->ToObject()->ForceSet(
+                            strLitToV8("bsonsize"),
+                            createV8Function(bsonsize)->GetFunction());
+    }
+
+
+    // ----- internal -----
+
+    void V8Scope::reset() {
+        V8_SIMPLE_HEADER
+        unregisterOpId();
+        _error = "";
+        _pendingKill = false;
+        _inNativeExecution = true;
+        registerOpId();
+    }
+
+    v8::Local<v8::Value> V8Scope::newFunction(const char *code) {
+        v8::HandleScope handle_scope;
+        v8::TryCatch try_catch;
+        string codeStr = str::stream() << "____MongoToV8_newFunction_temp = " << code;
+
+        v8::Local<v8::Script> compiled = v8::Script::New(v8::String::New(codeStr.c_str()));
+
+        // throw on compile error
+        checkV8ErrorState(compiled, try_catch);
+
+        v8::Local<v8::Value> ret = compiled->Run();
+
+        // throw on run/assignment error
+        checkV8ErrorState(ret, try_catch);
+
+        return handle_scope.Close(ret);
+    }
+
+    v8::Local<v8::Value> V8Scope::newId(const OID &id) {
+        v8::HandleScope handle_scope;
+        v8::Handle<v8::Function> idCons = ObjectIdFT()->GetFunction();
+        v8::Handle<v8::Value> argv[1];
+        argv[0] = v8::String::New(id.str().c_str());
+        return handle_scope.Close(idCons->NewInstance(1, argv));
+    }
+
+    /**
+     * converts a BSONObj to a Lazy V8 object
+     */
+    v8::Handle<v8::Object> V8Scope::mongoToLZV8(const BSONObj& m, bool readOnly) {
+        if (m.firstElementType() == String && str::equals(m.firstElementFieldName(), "$ref")) {
+            BSONObjIterator it(m);
+            const BSONElement ref = it.next();
+            const BSONElement id = it.next();
+            if (id.ok() && str::equals(id.fieldName(), "$id")) {
+                v8::Handle<v8::Value> args[] = {
+                    mongoToV8Element(ref, readOnly),
+                    mongoToV8Element(id, readOnly)
+                };
+                v8::Local<v8::Object> dbRef = DBRefFT()->GetFunction()->NewInstance(2, args);
+                while (it.more()) {
+                    BSONElement elem = it.next();
+                    dbRef->Set(v8StringData(elem.fieldName()), mongoToV8Element(elem, readOnly));
+                }
+                return dbRef;
+            }
+        }
+
+        v8::Handle<v8::FunctionTemplate> templ = readOnly ? ROBsonFT() : LazyBsonFT();
+        v8::Handle<v8::Object> o = templ->GetFunction()->NewInstance();
+        massert(16496, str::stream() << "V8: NULL Object template instantiated. "
+                                     << (v8::V8::IsExecutionTerminating() ?
+                                        "v8 execution is terminating." :
+                                        "v8 still executing."),
+                       *o != NULL);
+
+        wrapBSONObject(o, m, readOnly);
+        return o;
+    }
+
+    v8::Handle<v8::Value> V8Scope::mongoToV8Element(const BSONElement &elem, bool readOnly) {
+        v8::Handle<v8::Value> argv[3];      // arguments for v8 instance constructors
+        v8::Local<v8::Object> instance;     // instance of v8 type
+        uint64_t nativeUnsignedLong;        // native representation of NumberLong
+
+        switch (elem.type()) {
+        case mongo::Code:
+            return newFunction(elem.valuestr());
+        case CodeWScope:
+            if (!elem.codeWScopeObject().isEmpty())
+                log() << "warning: CodeWScope doesn't transfer to db.eval" << endl;
+            return newFunction(elem.codeWScopeCode());
+        case mongo::Symbol:
+        case mongo::String:
+            return v8::String::New(elem.valuestr());
+        case mongo::jstOID:
+            return newId(elem.__oid());
+        case mongo::NumberDouble:
+        case mongo::NumberInt:
+            return v8::Number::New(elem.number());
+        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
+
+            // 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:
+            return v8::Date::New((double) ((long long)elem.date().millis));
+        case mongo::Bool:
+            return v8::Boolean::New(elem.boolean());
+        case mongo::EOO:
+        case mongo::jstNULL:
+        case mongo::Undefined: // duplicate sm behavior
+            return v8::Null();
+        case mongo::RegEx: {
+            // TODO parse into a custom type that can support any patterns and flags SERVER-9803
+            v8::TryCatch tryCatch;
+
+            v8::Handle<v8::Value> args[] = {
+                v8::String::New(elem.regex()),
+                v8::String::New(elem.regexFlags())
+            };
+
+            v8::Handle<v8::Value> ret = _jsRegExpConstructor->NewInstance(2, args);
+            uassert(16863, str::stream() << "Error converting " << elem.toString(false)
+                                         << " in field " << elem.fieldName()
+                                         << " to a JS RegExp object: "
+                                         << toSTLString(tryCatch.Exception()),
+                    !tryCatch.HasCaught());
+
+            return ret;
+        }
+        case mongo::BinData: {
+            int len;
+            const char *data = elem.binData(len);
+            stringstream ss;
+            base64::encode(ss, data, len);
+            argv[0] = v8::Number::New(elem.binDataType());
+            argv[1] = v8::String::New(ss.str().c_str());
+            return BinDataFT()->GetFunction()->NewInstance(2, argv);
+        }
+        case mongo::Timestamp:
+            argv[0] = v8::Number::New(elem.timestampTime() / 1000);
+            argv[1] = v8::Number::New(elem.timestampInc());
+            return TimestampFT()->GetFunction()->NewInstance(2,argv);
+        case mongo::NumberLong:
+            nativeUnsignedLong = elem.numberLong();
+            // values above 2^53 are not accurately represented in JS
+            if ((long long)nativeUnsignedLong ==
+                (long long)(double)(long long)(nativeUnsignedLong) &&
+                    nativeUnsignedLong < 9007199254740992ULL) {
+                argv[0] = v8::Number::New((double)(long long)(nativeUnsignedLong));
+                return NumberLongFT()->GetFunction()->NewInstance(1, argv);
+            }
+            else {
+                argv[0] = v8::Number::New((double)(long long)(nativeUnsignedLong));
+                argv[1] = v8::Integer::New(nativeUnsignedLong >> 32);
+                argv[2] = v8::Integer::New((unsigned long)
+                                           (nativeUnsignedLong & 0x00000000ffffffff));
+                return NumberLongFT()->GetFunction()->NewInstance(3, argv);
+            }
+        case mongo::MinKey:
+            return MinKeyFT()->GetFunction()->NewInstance();
+        case mongo::MaxKey:
+            return MaxKeyFT()->GetFunction()->NewInstance();
+        case mongo::DBRef:
+            argv[0] = v8StringData(elem.dbrefNS());
+            argv[1] = newId(elem.dbrefOID());
+            return DBPointerFT()->GetFunction()->NewInstance(2, argv);
+        default:
+            massert(16661, str::stream() << "can't handle type: " << elem.type()
+                                         << " " << elem.toString(), false);
+            break;
+        }
+        return v8::Undefined();
+    }
+
+    void V8Scope::v8ToMongoNumber(BSONObjBuilder& b,
+                                  const StringData& elementName,
+                                  v8::Handle<v8::Number> value,
+                                  BSONObj* originalParent) {
+        double val = value->Value();
+        // if previous type was integer, keep it
+        int intval = static_cast<int>(val);
+        if (val == intval && originalParent) {
+            // This makes copying an object of numbers O(n**2) :(
+            BSONElement elmt = originalParent->getField(elementName);
+            if (elmt.type() == mongo::NumberInt) {
+                b.append(elementName, intval);
+                return;
+            }
+        }
+        b.append(elementName, val);
+    }
+
+    void V8Scope::v8ToMongoRegex(BSONObjBuilder& b,
+                                 const StringData& elementName,
+                                 v8::Handle<v8::RegExp> v8Regex) {
+        V8String v8RegexString (v8Regex);
+        StringData regex = v8RegexString;
+        regex = regex.substr(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 StringData& elementName,
+                                 v8::Handle<v8::Object> obj) {
+        verify(DBPointerFT()->HasInstance(obj));
+        v8::Local<v8::Value> theid = obj->Get(strLitToV8("id"));
+        OID oid = v8ToMongoObjectID(theid->ToObject());
+        string ns = toSTLString(obj->Get(strLitToV8("ns")));
+        b.appendDBRef(elementName, ns, oid);
+    }
+
+    void V8Scope::v8ToMongoBinData(BSONObjBuilder& b,
+                                   const StringData& elementName,
+                                   v8::Handle<v8::Object> obj) {
+
+        verify(BinDataFT()->HasInstance(obj));
+        verify(obj->InternalFieldCount() == 1);
+        int len = obj->Get(strLitToV8("len"))->ToInt32()->Value();
+        b.appendBinData(elementName,
+                        len,
+                        mongo::BinDataType(obj->Get(strLitToV8("type"))->ToInt32()->Value()),
+                        base64::decode(toSTLString(obj->GetInternalField(0))).c_str());
+    }
+
+    OID V8Scope::v8ToMongoObjectID(v8::Handle<v8::Object> obj) {
+        verify(ObjectIdFT()->HasInstance(obj));
+        const string hexStr = toSTLString(obj->Get(strLitToV8("str")));
+
+        // OID parser doesn't have user-friendly error messages
+        uassert(16864, "ObjectID.str must be exactly 24 chars long",
+                hexStr.size() == 24);
+        uassert(16865, "ObjectID.str must only have hex characters [0-1a-fA-F]",
+                count_if(hexStr.begin(), hexStr.end(), ::isxdigit) == 24);
+
+        return OID(hexStr);
+    }
+
+    void V8Scope::v8ToMongoObject(BSONObjBuilder& b,
+                                  const StringData& elementName,
+                                  v8::Handle<v8::Value> value,
+                                  int depth,
+                                  BSONObj* originalParent) {
+        verify(value->IsObject());
+        v8::Handle<v8::Object> obj = value.As<v8::Object>();
+
+        if (value->IsRegExp()) {
+            v8ToMongoRegex(b, elementName, obj.As<v8::RegExp>());
+        } else if (ObjectIdFT()->HasInstance(value)) {
+            b.append(elementName, v8ToMongoObjectID(obj));
+        } else if (NumberLongFT()->HasInstance(value)) {
+            b.append(elementName, numberLongVal(this, obj));
+        } else if (NumberIntFT()->HasInstance(value)) {
+            b.append(elementName, numberIntVal(this, obj));
+        } else if (DBPointerFT()->HasInstance(value)) {
+            v8ToMongoDBRef(b, elementName, obj);
+        } else if (BinDataFT()->HasInstance(value)) {
+            v8ToMongoBinData(b, elementName, obj);
+        } else if (TimestampFT()->HasInstance(value)) {
+            OpTime ot (obj->Get(strLitToV8("t"))->Uint32Value(),
+                       obj->Get(strLitToV8("i"))->Uint32Value());
+            b.append(elementName, ot);
+        } else if (MinKeyFT()->HasInstance(value)) {
+            b.appendMinKey(elementName);
+        } else if (MaxKeyFT()->HasInstance(value)) {
+            b.appendMaxKey(elementName);
+        } else {
+            // nested object or array
+            BSONObj sub = v8ToMongo(obj, depth);
+            b.append(elementName, sub);
+        }
+    }
+
+    void V8Scope::v8ToMongoElement(BSONObjBuilder & b, const StringData& sname,
+                                   v8::Handle<v8::Value> value, int depth,
+                                   BSONObj* originalParent) {
+
+        // Null char should be at the end, not in the string
+        uassert(16985,
+                str::stream() << "JavaScript property (name) contains a null char "
+                              << "which is not allowed in BSON. "
+                              << originalParent->jsonString(),
+                (string::npos == sname.find('\0')) );
+
+        if (value->IsString()) {
+            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, V8String(value));
+            return;
+        }
+        if (value->IsNumber()) {
+            v8ToMongoNumber(b, sname, value.As<v8::Number>(), originalParent);
+            return;
+        }
+        if (value->IsArray()) {
+            // Note: can't use BSONArrayBuilder because need to call recursively
+            BSONObjBuilder arrBuilder(b.subarrayStart(sname));
+            v8::Handle<v8::Array> array = value.As<v8::Array>();
+            const int len = array->Length();
+            for (int i=0; i < len; i++) {
+                const string name = BSONObjBuilder::numStr(i);
+                v8ToMongoElement(arrBuilder, name, array->Get(i), depth+1, originalParent);
+            }
+            return;
+        }
+        if (value->IsDate()) {
+            long long dateval = (long long)(v8::Date::Cast(*value)->NumberValue());
+            b.appendDate(sname, Date_t((unsigned long long) dateval));
+            return;
+        }
+        if (value->IsExternal())
+            return;
+        if (value->IsObject()) {
+            v8ToMongoObject(b, sname, value, depth, originalParent);
+            return;
+        }
+
+        if (value->IsBoolean()) {
+            b.appendBool(sname, value->ToBoolean()->Value());
+            return;
+        }
+        else if (value->IsUndefined()) {
+            b.appendUndefined(sname);
+            return;
+        }
+        else if (value->IsNull()) {
+            b.appendNull(sname);
+            return;
+        }
+        uasserted(16662, str::stream() << "unable to convert JavaScript property to mongo element "
+                                   << sname);
+    }
+
+    BSONObj V8Scope::v8ToMongo(v8::Handle<v8::Object> o, int depth) {
+        BSONObj originalBSON;
+        if (LazyBsonFT()->HasInstance(o)) {
+            originalBSON = unwrapBSONObj(this, o);
+            BSONHolder* holder = unwrapHolder(this, o);
+            if (holder && !holder->_modified) {
+                // object was not modified, use bson as is
+                return originalBSON;
+            }
+        }
+
+        BSONObjBuilder b;
+
+        // 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(strLitToV8("_id"))) {
+                v8ToMongoElement(b, "_id", o->Get(strLitToV8("_id")), 0, &originalBSON);
+            }
+        }
+
+        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();
+
+            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();
+    }
+
+    // --- random utils ----
+
+    v8::Handle<v8::Value> V8Scope::Print(V8Scope* scope, const v8::Arguments& args) {
+        stringstream ss;
+        v8::HandleScope handle_scope;
+        bool first = true;
+        for (int i = 0; i < args.Length(); i++) {
+            if (first)
+                first = false;
+            else
+                ss << " ";
+
+            if (args[i].IsEmpty()) {
+                // failed to get object to convert
+                ss << "[unknown type]";
+                continue;
+            }
+            if (args[i]->IsExternal()) {
+                // object is External
+                ss << "[mongo internal]";
+                continue;
+            }
+
+            v8::String::Utf8Value str(args[i]);
+            ss << *str;
+        }
+        ss << "\n";
+        Logstream::logLockless(ss.str());
+        return handle_scope.Close(v8::Undefined());
+    }
+
+    v8::Handle<v8::Value> V8Scope::Version(V8Scope* scope, const v8::Arguments& args) {
+        v8::HandleScope handle_scope;
+        return handle_scope.Close(v8::String::New(v8::V8::GetVersion()));
+    }
+
+    v8::Handle<v8::Value> V8Scope::GCV8(V8Scope* scope, const v8::Arguments& args) {
+        // trigger low memory notification.  for more granular control over garbage
+        // collection cycle, @see v8::V8::IdleNotification.
+        v8::V8::LowMemoryNotification();
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> V8Scope::startCpuProfiler(V8Scope* scope, const v8::Arguments& args) {
+        if (args.Length() != 1 || !args[0]->IsString()) {
+            return v8AssertionException("startCpuProfiler takes a string argument");
+        }
+        scope->_cpuProfiler.start(*v8::String::Utf8Value(args[0]->ToString()));
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> V8Scope::stopCpuProfiler(V8Scope* scope, const v8::Arguments& args) {
+        if (args.Length() != 1 || !args[0]->IsString()) {
+            return v8AssertionException("stopCpuProfiler takes a string argument");
+        }
+        scope->_cpuProfiler.stop(*v8::String::Utf8Value(args[0]->ToString()));
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> V8Scope::getCpuProfile(V8Scope* scope, const v8::Arguments& args) {
+        if (args.Length() != 1 || !args[0]->IsString()) {
+            return v8AssertionException("getCpuProfile takes a string argument");
+        }
+        return scope->mongoToLZV8(scope->_cpuProfiler.fetch(
+                *v8::String::Utf8Value(args[0]->ToString())));
+    }
+
+} // namespace mongo
Index: mongodb-src-r2.4.10/src/mongo/scripting/engine_v8-3.14.h
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/engine_v8-3.14.h
@@ -0,0 +1,560 @@
+//engine_v8.h
+
+/*    Copyright 2009 10gen Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <v8.h>
+#include <vector>
+
+#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-3.14_profiler.h"
+
+/**
+ * V8_SIMPLE_HEADER must be placed in any function called from a public API
+ * that work with v8 handles (and/or must be within the V8Scope's isolate
+ * and context).  Be sure to close the handle_scope if returning a v8::Handle!
+ */
+#define V8_SIMPLE_HEADER                                                                      \
+        v8::Locker v8lock(_isolate);          /* acquire isolate lock */                      \
+        v8::Isolate::Scope iscope(_isolate);  /* enter the isolate; exit when out of scope */ \
+        v8::HandleScope handle_scope;         /* make the current scope own local handles */  \
+        v8::Context::Scope context_scope(_context); /* enter the context; exit when out of scope */
+
+namespace mongo {
+
+    class V8ScriptEngine;
+    class V8Scope;
+    class BSONHolder;
+
+    typedef v8::Handle<v8::Value> (*v8Function)(V8Scope* scope, const v8::Arguments& args);
+
+    /**
+     * The ObjTracker class keeps track of all weakly referenced v8 objects.  This is
+     * required because v8 does not invoke the WeakReferenceCallback when shutting down
+     * the context/isolate.  To track a new object, add an ObjTracker<MyObjType> member
+     * variable to the V8Scope (if one does not already exist for that type).  Instead
+     * of calling v8::Persistent::MakeWeak() directly, simply invoke track() with the
+     * persistent handle and the pointer to be freed.
+     */
+    template <typename _ObjType>
+    class ObjTracker {
+    public:
+        /** Track an object to be freed when it is no longer referenced in JavaScript.
+         * @param  instanceHandle  persistent handle to the weakly referenced object
+         * @param  rawData         pointer to the object instance
+         */
+        void track(v8::Persistent<v8::Value> instanceHandle, _ObjType* instance) {
+            TrackedPtr* collectionHandle = new TrackedPtr(instance, this);
+            _container.insert(collectionHandle);
+            instanceHandle.MakeWeak(collectionHandle, deleteOnCollect);
+        }
+        /**
+         * Free any remaining objects and their TrackedPtrs.  Invoked when the
+         * V8Scope is destructed.
+         */
+        ~ObjTracker() {
+            if (!_container.empty())
+                LOG(1) << "freeing " << _container.size() << " uncollected "
+                       << typeid(_ObjType).name() << " objects" << endl;
+            typename set<TrackedPtr*>::iterator it = _container.begin();
+            while (it != _container.end()) {
+                delete *it;
+                _container.erase(it++);
+            }
+        }
+    private:
+        /**
+         * Simple struct which contains a pointer to the tracked object, and a pointer
+         * to the ObjTracker which owns it.  This is the argument supplied to v8's
+         * WeakReferenceCallback and MakeWeak().
+         */
+        struct TrackedPtr {
+        public:
+            TrackedPtr(_ObjType* instance, ObjTracker<_ObjType>* tracker) :
+                _objPtr(instance),
+                _tracker(tracker) { }
+            scoped_ptr<_ObjType> _objPtr;
+            ObjTracker<_ObjType>* _tracker;
+        };
+
+        /**
+         * v8 callback for weak persistent handles that have been marked for removal by the
+         * garbage collector.  Signature conforms to v8's WeakReferenceCallback.
+         * @param  instanceHandle  persistent handle to the weakly referenced object
+         * @param  rawData         pointer to the TrackedPtr instance
+         */
+        static void deleteOnCollect(v8::Persistent<v8::Value> instanceHandle, void* rawData) {
+            TrackedPtr* trackedPtr = static_cast<TrackedPtr*>(rawData);
+            trackedPtr->_tracker->_container.erase(trackedPtr);
+            delete trackedPtr;
+            instanceHandle.Dispose();
+        }
+
+        // container for all TrackedPtrs created by this ObjTracker instance
+        set<TrackedPtr*> _container;
+    };
+
+    /**
+     * A V8Scope represents a unit of javascript execution environment; specifically a single
+     * isolate and a single context executing in a single mongo thread.  A V8Scope can be reused
+     * in another thread only after reset() has been called.
+     *
+     * NB:
+     *   - v8 objects/handles/etc. cannot be shared between V8Scopes
+     *   - in mongod, each scope is associated with an opId (for KillOp support)
+     *   - any public functions that call the v8 API should use a V8_SIMPLE_HEADER
+     *   - the caller of any public function that returns a v8 type or has a v8 handle argument
+     *         must enter the isolate, context, and set up the appropriate handle scope
+     */
+    class V8Scope : public Scope {
+    public:
+
+        V8Scope(V8ScriptEngine* engine);
+        ~V8Scope();
+
+        virtual void init(const BSONObj* data);
+
+        /**
+         * Reset the state of this scope for use by another thread or operation
+         */
+        virtual void reset();
+
+        /**
+         * Terminate this scope
+         */
+        virtual void kill();
+
+        /** check if there is a pending killOp request */
+        bool isKillPending() const;
+
+        /**
+         * Connect to a local database, create a Mongo object instance, and load any
+         * server-side js into the global object
+         */
+        virtual void localConnect(const char* dbName);
+
+        virtual void externalSetup();
+
+        virtual void installDBAccess();
+
+        virtual void installBSONTypes();
+
+        virtual string getError() { return _error; }
+
+        virtual bool hasOutOfMemoryException();
+
+        /**
+         * Run the garbage collector on this scope (native function).  @see GCV8 for the
+         * javascript binding version.
+         */
+        void gc();
+
+        /**
+         * get a global property.  caller must set up the v8 state.
+         */
+        v8::Handle<v8::Value> get(const char* field);
+
+        virtual double getNumber(const char* field);
+        virtual int getNumberInt(const char* field);
+        virtual long long getNumberLongLong(const char* field);
+        virtual string getString(const char* field);
+        virtual bool getBoolean(const char* field);
+        virtual BSONObj getObject(const char* field);
+
+        virtual void setNumber(const char* field, double val);
+        virtual void setString(const char* field, const char* val);
+        virtual void setBoolean(const char* field, bool val);
+        virtual void setElement(const char* field, const BSONElement& e);
+        virtual void setObject(const char* field, const BSONObj& obj, bool readOnly);
+        virtual void setFunction(const char* field, const char* code);
+
+        virtual int type(const char* field);
+
+        virtual void rename(const char* from, const char* to);
+
+        virtual int invoke(ScriptingFunction func, const BSONObj* args, const BSONObj* recv,
+                           int timeoutMs = 0, bool ignoreReturn = false,
+                           bool readOnlyArgs = false, bool readOnlyRecv = false);
+
+        virtual bool exec(const StringData& code, const string& name, bool printResult,
+                          bool reportError, bool assertOnError, int timeoutMs);
+
+        // functions to create v8 object and function templates
+        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);
+
+        // These functions inject a function (either an unwrapped function pointer or a pre-wrapped
+        // FunctionTemplate) into the provided object. If no object is provided, the function will
+        // be injected at global scope. These functions take care of setting the function and class
+        // name on the returned FunctionTemplate.
+        v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name, v8Function func);
+        v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name,
+                                                          v8Function func,
+                                                          v8::Handle<v8::Object>& obj);
+        v8::Handle<v8::FunctionTemplate> injectV8Function(const char* name,
+                                                          v8::Handle<v8::FunctionTemplate> ft,
+                                                          v8::Handle<v8::Object>& obj);
+
+        // Injects a method into the provided prototype
+        v8::Handle<v8::FunctionTemplate> injectV8Method(const char* name,
+                                                        v8Function func,
+                                                        v8::Handle<v8::ObjectTemplate>& proto);
+        v8::Handle<v8::FunctionTemplate> createV8Function(v8Function func);
+        virtual ScriptingFunction _createFunction(const char* code,
+                                                  ScriptingFunction functionNumber = 0);
+        v8::Local<v8::Function> __createFunction(const char* code,
+                                                 ScriptingFunction functionNumber = 0);
+
+        /**
+         * Convert BSON types to v8 Javascript types
+         */
+        v8::Handle<v8::Object> mongoToLZV8(const mongo::BSONObj& m, bool readOnly = false);
+        v8::Handle<v8::Value> mongoToV8Element(const BSONElement& f, bool readOnly = false);
+
+        /**
+         * Convert v8 Javascript types to BSON types
+         */
+        mongo::BSONObj v8ToMongo(v8::Handle<v8::Object> obj, int depth = 0);
+        void v8ToMongoElement(BSONObjBuilder& b,
+                              const StringData& sname,
+                              v8::Handle<v8::Value> value,
+                              int depth = 0,
+                              BSONObj* originalParent = 0);
+        void v8ToMongoObject(BSONObjBuilder& b,
+                             const StringData& sname,
+                             v8::Handle<v8::Value> value,
+                             int depth,
+                             BSONObj* originalParent);
+        void v8ToMongoNumber(BSONObjBuilder& b,
+                             const StringData& elementName,
+                             v8::Handle<v8::Number> value,
+                             BSONObj* originalParent);
+        void v8ToMongoRegex(BSONObjBuilder& b,
+                            const StringData& elementName,
+                            v8::Handle<v8::RegExp> v8Regex);
+        void v8ToMongoDBRef(BSONObjBuilder& b,
+                            const StringData& elementName,
+                            v8::Handle<v8::Object> obj);
+        void v8ToMongoBinData(BSONObjBuilder& b,
+                              const StringData& elementName,
+                              v8::Handle<v8::Object> obj);
+        OID v8ToMongoObjectID(v8::Handle<v8::Object> obj);
+
+        v8::Local<v8::Value> newId(const OID& id);
+
+        /**
+         * Convert a JavaScript exception to a stl string.  Requires
+         * access to the V8Scope instance to report source context information.
+         */
+        std::string v8ExceptionToSTLString(const v8::TryCatch* try_catch);
+
+        /**
+         * Create a V8 string with a local handle
+         */
+        static inline v8::Handle<v8::String> v8StringData(StringData str) {
+            return v8::String::New(str.rawData());
+        }
+
+        /**
+         * Get the isolate this scope belongs to (can be called from any thread, but v8 requires
+         *  the new thread enter the isolate and context.  Only one thread can enter the isolate.
+         */
+        v8::Isolate* getIsolate() { return _isolate; }
+
+        /**
+         * Get the JS context this scope executes within.
+         */
+        v8::Persistent<v8::Context> getContext() { return _context; }
+
+        /**
+         * Get the global JS object
+         */
+        v8::Persistent<v8::Object> getGlobal() { return _global; }
+
+        ObjTracker<BSONHolder> bsonHolderTracker;
+        ObjTracker<DBClientWithCommands> dbClientWithCommandsTracker;
+        ObjTracker<DBClientBase> dbClientBaseTracker;
+        ObjTracker<DBClientCursor> dbClientCursorTracker;
+
+        // These are all named after the JS constructor name + FT
+        v8::Handle<v8::FunctionTemplate> ObjectIdFT()       const { return _ObjectIdFT; }
+        v8::Handle<v8::FunctionTemplate> DBRefFT()          const { return _DBRefFT; }
+        v8::Handle<v8::FunctionTemplate> DBPointerFT()      const { return _DBPointerFT; }
+        v8::Handle<v8::FunctionTemplate> BinDataFT()        const { return _BinDataFT; }
+        v8::Handle<v8::FunctionTemplate> NumberLongFT()     const { return _NumberLongFT; }
+        v8::Handle<v8::FunctionTemplate> NumberIntFT()      const { return _NumberIntFT; }
+        v8::Handle<v8::FunctionTemplate> TimestampFT()      const { return _TimestampFT; }
+        v8::Handle<v8::FunctionTemplate> MinKeyFT()         const { return _MinKeyFT; }
+        v8::Handle<v8::FunctionTemplate> MaxKeyFT()         const { return _MaxKeyFT; }
+        v8::Handle<v8::FunctionTemplate> MongoFT()          const { return _MongoFT; }
+        v8::Handle<v8::FunctionTemplate> DBFT()             const { return _DBFT; }
+        v8::Handle<v8::FunctionTemplate> DBCollectionFT()   const { return _DBCollectionFT; }
+        v8::Handle<v8::FunctionTemplate> DBQueryFT()        const { return _DBQueryFT; }
+        v8::Handle<v8::FunctionTemplate> InternalCursorFT() const { return _InternalCursorFT; }
+        v8::Handle<v8::FunctionTemplate> LazyBsonFT()       const { return _LazyBsonFT; }
+        v8::Handle<v8::FunctionTemplate> ROBsonFT()         const { return _ROBsonFT; }
+
+        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;
+        }
+
+    private:
+
+        /**
+         * Attach data to obj such that the data has the same lifetime as the Object obj points to.
+         * obj must have been created by either LazyBsonFT or ROBsonFT.
+         */
+        void wrapBSONObject(v8::Handle<v8::Object> obj, BSONObj data, bool readOnly);
+
+        /**
+         * Trampoline to call a c++ function with a specific signature (V8Scope*, v8::Arguments&).
+         * Handles interruption, exceptions, etc.
+         */
+        static v8::Handle<v8::Value> v8Callback(const v8::Arguments& args);
+
+        /**
+         * Interpreter agnostic 'Native Callback' trampoline.  Note this is only called
+         * from v8Callback().
+         */
+        static v8::Handle<v8::Value> nativeCallback(V8Scope* scope, const v8::Arguments& args);
+
+        /**
+         * v8-specific implementations of basic global functions
+         */
+        static v8::Handle<v8::Value> load(V8Scope* scope, const v8::Arguments& args);
+        static v8::Handle<v8::Value> Print(V8Scope* scope, const v8::Arguments& args);
+        static v8::Handle<v8::Value> Version(V8Scope* scope, const v8::Arguments& args);
+        static v8::Handle<v8::Value> GCV8(V8Scope* scope, const v8::Arguments& args);
+
+        static v8::Handle<v8::Value> startCpuProfiler(V8Scope* scope, const v8::Arguments& args);
+        static v8::Handle<v8::Value> stopCpuProfiler(V8Scope* scope, const v8::Arguments& args);
+        static v8::Handle<v8::Value> getCpuProfile(V8Scope* scope, const v8::Arguments& args);
+
+        /** Signal that this scope has entered a native (C++) execution context.
+         *  @return  false if execution has been interrupted
+         */
+        bool nativePrologue();
+
+        /** Signal that this scope has completed native execution and is returning to v8.
+         *  @return  false if execution has been interrupted
+         */
+        bool nativeEpilogue();
+
+        /**
+         * Register this scope with the mongo op id.  If executing outside the
+         * context of a mongo operation (e.g. from the shell), killOp will not
+         * be supported.
+         */
+        void registerOpId();
+
+        /**
+         * Unregister this scope with the mongo op id.
+         */
+        void unregisterOpId();
+
+        /**
+         * Create a new function; primarily used for BSON/V8 conversion.
+         */
+        v8::Local<v8::Value> newFunction(const char *code);
+
+        template <typename _HandleType>
+        bool checkV8ErrorState(const _HandleType& resultHandle,
+                               const v8::TryCatch& try_catch,
+                               bool reportError = true,
+                               bool assertOnError = true);
+
+        V8ScriptEngine* _engine;
+
+        v8::Persistent<v8::Context> _context;
+        v8::Persistent<v8::Object> _global;
+        string _error;
+        vector<v8::Persistent<v8::Value> > _funcs;
+
+        enum ConnectState { NOT, LOCAL, EXTERNAL };
+        ConnectState _connectState;
+
+        // These are all named after the JS constructor name + FT
+        v8::Persistent<v8::FunctionTemplate> _ObjectIdFT;
+        v8::Persistent<v8::FunctionTemplate> _DBRefFT;
+        v8::Persistent<v8::FunctionTemplate> _DBPointerFT;
+        v8::Persistent<v8::FunctionTemplate> _BinDataFT;
+        v8::Persistent<v8::FunctionTemplate> _NumberLongFT;
+        v8::Persistent<v8::FunctionTemplate> _NumberIntFT;
+        v8::Persistent<v8::FunctionTemplate> _TimestampFT;
+        v8::Persistent<v8::FunctionTemplate> _MinKeyFT;
+        v8::Persistent<v8::FunctionTemplate> _MaxKeyFT;
+        v8::Persistent<v8::FunctionTemplate> _MongoFT;
+        v8::Persistent<v8::FunctionTemplate> _DBFT;
+        v8::Persistent<v8::FunctionTemplate> _DBCollectionFT;
+        v8::Persistent<v8::FunctionTemplate> _DBQueryFT;
+        v8::Persistent<v8::FunctionTemplate> _InternalCursorFT;
+        v8::Persistent<v8::FunctionTemplate> _LazyBsonFT;
+        v8::Persistent<v8::FunctionTemplate> _ROBsonFT;
+
+        v8::Persistent<v8::Function> _jsRegExpConstructor;
+
+        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
+        int _opId;                   // op id for this scope
+    };
+
+    /// Helper to extract V8Scope for an Isolate
+    inline V8Scope* getScope(v8::Isolate* isolate) {
+        return static_cast<V8Scope*>(isolate->GetData());
+    }
+
+    class V8ScriptEngine : public ScriptEngine {
+    public:
+        V8ScriptEngine();
+        virtual ~V8ScriptEngine();
+        virtual Scope* createScope() { return new V8Scope(this); }
+        virtual void runTest() {}
+        bool utf8Ok() const { return true; }
+
+        /**
+         * Interrupt a single active v8 execution context
+         * NB: To interrupt a context, we must acquire the following locks (in order):
+         *       - mutex to protect the the map of all scopes (_globalInterruptLock)
+         *       - mutex to protect the scope that's being interrupted (_interruptLock)
+         * The scope will be removed from the map upon destruction, and the op id
+         * will be updated if the scope is ever reused from a pool.
+         */
+        virtual void interrupt(unsigned opId);
+
+        /**
+         * Interrupt all v8 contexts (and isolates).  @see interrupt().
+         */
+        virtual void interruptAll();
+
+    private:
+        friend class V8Scope;
+
+        std::string printKnownOps_inlock();
+
+        /**
+         * Get the deadline monitor instance for the v8 ScriptEngine
+         */
+        DeadlineMonitor<V8Scope>* getDeadlineMonitor() { return &_deadlineMonitor; }
+
+        typedef map<unsigned, V8Scope*> OpIdToScopeMap;
+        mongo::mutex _globalInterruptLock;  // protects map of all operation ids -> scope
+        OpIdToScopeMap _opToScopeMap;       // map of mongo op ids to scopes (protected by
+                                            // _globalInterruptLock).
+        DeadlineMonitor<V8Scope> _deadlineMonitor;
+    };
+
+    class BSONHolder {
+    MONGO_DISALLOW_COPYING(BSONHolder);
+    public:
+        explicit BSONHolder(BSONObj obj) :
+            _scope(NULL),
+            _obj(obj.getOwned()),
+            _modified(false) {
+            // give hint v8's GC
+            v8::V8::AdjustAmountOfExternalAllocatedMemory(_obj.objsize());
+        }
+        ~BSONHolder() {
+            if (_scope && _scope->getIsolate())
+                // if v8 is still up, send hint to GC
+                v8::V8::AdjustAmountOfExternalAllocatedMemory(-_obj.objsize());
+        }
+        V8Scope* _scope;
+        BSONObj _obj;
+        bool _modified;
+        bool _readOnly;
+        set<string> _removed;
+    };
+
+    /**
+     * Check for an error condition (e.g. empty handle, JS exception, OOM) after executing
+     * a v8 operation.
+     * @resultHandle         handle storing the result of the preceeding v8 operation
+     * @try_catch            the active v8::TryCatch exception handler
+     * @param reportError    if true, log an error message
+     * @param assertOnError  if true, throw an exception if an error is detected
+     *                       if false, return value indicates error state
+     * @return true if an error was detected and assertOnError is set to false
+     *         false if no error was detected
+     */
+    template <typename _HandleType>
+    bool V8Scope::checkV8ErrorState(const _HandleType& resultHandle,
+                                    const v8::TryCatch& try_catch,
+                                    bool reportError,
+                                    bool assertOnError) {
+        bool haveError = false;
+
+        if (try_catch.HasCaught() && try_catch.CanContinue()) {
+            // normal JS exception
+            _error = v8ExceptionToSTLString(&try_catch);
+            haveError = true;
+        }
+        else if (hasOutOfMemoryException()) {
+            // out of memory exception (treated as terminal)
+            _error = "JavaScript execution failed -- v8 is out of memory";
+            haveError = true;
+        }
+        else if (resultHandle.IsEmpty() || try_catch.HasCaught()) {
+            // terminal exception (due to empty handle, termination, etc.)
+            _error = "JavaScript execution failed";
+            haveError = true;
+        }
+
+        if (haveError) {
+            if (reportError)
+                log() << _error << endl;
+            if (assertOnError)
+                uasserted(16722, _error);
+            return true;
+        }
+
+        return false;
+    }
+
+    extern ScriptEngine* globalScriptEngine;
+
+}
Index: mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_db.cpp
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_db.cpp
@@ -0,0 +1,981 @@
+// v8_db.cpp
+
+/*    Copyright 2009 10gen 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/>.
+ */
+
+#include "mongo/scripting/v8-3.14_db.h"
+
+#include <iostream>
+#include <boost/scoped_array.hpp>
+
+#include "mongo/base/init.h"
+#include "mongo/client/sasl_client_authenticate.h"
+#include "mongo/client/syncclusterconnection.h"
+#include "mongo/db/namespacestring.h"
+#include "mongo/s/d_logic.h"
+#include "mongo/scripting/engine_v8-3.14.h"
+#include "mongo/scripting/v8-3.14_utils.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/base64.h"
+#include "mongo/util/text.h"
+
+using namespace std;
+
+namespace mongo {
+
+    namespace {
+        std::vector<V8FunctionPrototypeManipulatorFn> _mongoPrototypeManipulators;
+        bool _mongoPrototypeManipulatorsFrozen = false;
+
+        MONGO_INITIALIZER(V8MongoPrototypeManipulatorRegistry)(InitializerContext* context) {
+            return Status::OK();
+        }
+
+        MONGO_INITIALIZER_WITH_PREREQUISITES(V8MongoPrototypeManipulatorRegistrationDone,
+                                             ("V8MongoPrototypeManipulatorRegistry"))
+            (InitializerContext* context) {
+
+            _mongoPrototypeManipulatorsFrozen = true;
+            return Status::OK();
+        }
+
+    }  // namespace
+
+    void v8RegisterMongoPrototypeManipulator(const V8FunctionPrototypeManipulatorFn& manipulator) {
+        fassert(16467, !_mongoPrototypeManipulatorsFrozen);
+        _mongoPrototypeManipulators.push_back(manipulator);
+    }
+
+    static v8::Handle<v8::Value> newInstance(v8::Handle<v8::Function> f, const v8::Arguments& args) {
+        // need to translate arguments into an array
+        v8::HandleScope handle_scope;
+        const int argc = args.Length();
+        static const int MAX_ARGC = 24;
+        uassert(16858, "Too many arguments. Max is 24",
+                argc <= MAX_ARGC);
+
+        // TODO SERVER-8016: properly allocate handles on the stack
+        v8::Handle<v8::Value> argv[MAX_ARGC];
+        for (int i = 0; i < argc; ++i) {
+            argv[i] = args[i];
+        }
+        return handle_scope.Close(f->NewInstance(argc, argv));
+    }
+
+    v8::Handle<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope) {
+        v8::Handle<v8::FunctionTemplate> ic = scope->createV8Function(internalCursorCons);
+        ic->InstanceTemplate()->SetInternalFieldCount(1);
+        v8::Handle<v8::ObjectTemplate> icproto = ic->PrototypeTemplate();
+        scope->injectV8Method("next", internalCursorNext, icproto);
+        scope->injectV8Method("hasNext", internalCursorHasNext, icproto);
+        scope->injectV8Method("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto);
+        scope->injectV8Method("readOnly", internalCursorReadOnly, icproto);
+        return ic;
+    }
+
+    v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scope, bool local) {
+        v8::Handle<v8::FunctionTemplate> mongo;
+        if (local)
+            mongo = scope->createV8Function(mongoConsLocal);
+        else
+            mongo = scope->createV8Function(mongoConsExternal);
+        mongo->InstanceTemplate()->SetInternalFieldCount(1);
+        v8::Handle<v8::ObjectTemplate> proto = mongo->PrototypeTemplate();
+        scope->injectV8Method("find", mongoFind, proto);
+        scope->injectV8Method("insert", mongoInsert, proto);
+        scope->injectV8Method("remove", mongoRemove, proto);
+        scope->injectV8Method("update", mongoUpdate, proto);
+        scope->injectV8Method("auth", mongoAuth, proto);
+        scope->injectV8Method("logout", mongoLogout, proto);
+
+        fassert(16468, _mongoPrototypeManipulatorsFrozen);
+        for (size_t i = 0; i < _mongoPrototypeManipulators.size(); ++i)
+            _mongoPrototypeManipulators[i](scope, mongo);
+
+        return mongo;
+    }
+
+
+    v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Arguments& args) {
+        char host[255];
+        if (args.Length() > 0 && args[0]->IsString()) {
+            uassert(16666, "string argument too long", args[0]->ToString()->Utf8Length() < 250);
+            args[0]->ToString()->WriteAscii(host);
+        }
+        else {
+            strcpy(host, "127.0.0.1");
+        }
+
+        // only allow function template to be used by a constructor
+        uassert(16859, "Mongo function is only usable as a constructor",
+                args.IsConstructCall());
+        verify(scope->MongoFT()->HasInstance(args.This()));
+
+        string errmsg;
+        ConnectionString cs = ConnectionString::parse(host, errmsg);
+        if (!cs.isValid()) {
+            return v8AssertionException(errmsg);
+        }
+
+        DBClientWithCommands* conn;
+        conn = cs.connect(errmsg);
+        if (!conn) {
+            return v8AssertionException(errmsg);
+        }
+
+        v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.This());
+        scope->dbClientWithCommandsTracker.track(self, conn);
+
+        ScriptEngine::runConnectCallback(*conn);
+
+        args.This()->SetInternalField(0, v8::External::New(conn));
+        args.This()->ForceSet(scope->v8StringData("slaveOk"), v8::Boolean::New(false));
+        args.This()->ForceSet(scope->v8StringData("host"), scope->v8StringData(host));
+
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 0, "local Mongo constructor takes no args")
+
+        // only allow function template to be used by a constructor
+        uassert(16860, "Mongo function is only usable as a constructor",
+                args.IsConstructCall());
+        verify(scope->MongoFT()->HasInstance(args.This()));
+
+        DBClientBase* conn = createDirectClient();
+        v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.This());
+        scope->dbClientBaseTracker.track(self, conn);
+
+        args.This()->SetInternalField(0, v8::External::New(conn));
+        args.This()->ForceSet(scope->v8StringData("slaveOk"), v8::Boolean::New(false));
+        args.This()->ForceSet(scope->v8StringData("host"), scope->v8StringData("EMBEDDED"));
+
+        return v8::Undefined();
+    }
+
+    DBClientBase* getConnection(V8Scope* scope, const v8::Arguments& args) {
+        verify(scope->MongoFT()->HasInstance(args.This()));
+        verify(args.This()->InternalFieldCount() == 1);
+        v8::Local<v8::External> c = v8::External::Cast(*(args.This()->GetInternalField(0)));
+        DBClientBase* conn = (DBClientBase*)(c->Value());
+        massert(16667, "Unable to get db client connection", conn);
+        return conn;
+    }
+
+    /**
+     * JavaScript binding for Mongo.prototype.find(namespace, query, fields, limit, skip)
+     */
+    v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 7, "find needs 7 args")
+        argumentCheck(args[1]->IsObject(), "needs to be an object")
+        DBClientBase * conn = getConnection(scope, args);
+        const string ns = toSTLString(args[0]);
+        BSONObj fields;
+        BSONObj q = scope->v8ToMongo(args[1]->ToObject());
+        bool haveFields = args[2]->IsObject() &&
+                          args[2]->ToObject()->GetPropertyNames()->Length() > 0;
+        if (haveFields)
+            fields = scope->v8ToMongo(args[2]->ToObject());
+
+        auto_ptr<mongo::DBClientCursor> cursor;
+        int nToReturn = args[3]->Int32Value();
+        int nToSkip = args[4]->Int32Value();
+        int batchSize = args[5]->Int32Value();
+        int options = args[6]->Int32Value();
+        cursor = conn->query(ns, q,  nToReturn, nToSkip, haveFields ? &fields : NULL,
+                                options, batchSize);
+        if (!cursor.get()) {
+            return v8AssertionException("error doing query: failed");
+        }
+
+        v8::Handle<v8::Function> cons = scope->InternalCursorFT()->GetFunction();
+        v8::Persistent<v8::Object> c = v8::Persistent<v8::Object>::New(cons->NewInstance());
+        c->SetInternalField(0, v8::External::New(cursor.get()));
+        scope->dbClientCursorTracker.track(c, cursor.release());
+        return c;
+    }
+
+    v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 3 ,"insert needs 3 args")
+        argumentCheck(args[1]->IsObject() ,"attempted to insert a non-object")
+
+        verify(scope->MongoFT()->HasInstance(args.This()));
+
+        if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) {
+            return v8AssertionException("js db in read only mode");
+        }
+
+        DBClientBase * conn = getConnection(scope, args);
+        const string ns = toSTLString(args[0]);
+
+        v8::Handle<v8::Integer> flags = args[2]->ToInteger();
+
+        if(args[1]->IsArray()){
+            v8::Local<v8::Array> arr = v8::Array::Cast(*args[1]);
+            vector<BSONObj> bos;
+            uint32_t len = arr->Length();
+            argumentCheck(len > 0, "attempted to insert an empty array")
+
+            for(uint32_t i = 0; i < len; i++){
+                v8::Local<v8::Object> el = arr->CloneElementAt(i);
+                argumentCheck(!el.IsEmpty(), "attempted to insert an array of non-object types")
+
+                // Set ID on the element if necessary
+                if (!el->Has(scope->v8StringData("_id"))) {
+                    v8::Handle<v8::Value> argv[1];
+                    el->ForceSet(scope->v8StringData("_id"),
+                                 scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv));
+                }
+                bos.push_back(scope->v8ToMongo(el));
+            }
+            conn->insert(ns, bos, flags->Int32Value());
+        }
+        else {
+            v8::Handle<v8::Object> in = args[1]->ToObject();
+            if (!in->Has(scope->v8StringData("_id"))) {
+                v8::Handle<v8::Value> argv[1];
+                in->ForceSet(scope->v8StringData("_id"),
+                             scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv));
+            }
+            BSONObj o = scope->v8ToMongo(in);
+            conn->insert(ns, o);
+        }
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 2 || args.Length() == 3, "remove needs 2 or 3 args")
+        argumentCheck(args[1]->IsObject(), "attempted to remove a non-object")
+
+        verify(scope->MongoFT()->HasInstance(args.This()));
+
+        if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) {
+            return v8AssertionException("js db in read only mode");
+        }
+
+        DBClientBase * conn = getConnection(scope, args);
+        const string ns = toSTLString(args[0]);
+
+        v8::Handle<v8::Object> in = args[1]->ToObject();
+        BSONObj o = scope->v8ToMongo(in);
+
+        bool justOne = false;
+        if (args.Length() > 2) {
+            justOne = args[2]->BooleanValue();
+        }
+
+        conn->remove(ns, o, justOne);
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() >= 3, "update needs at least 3 args")
+        argumentCheck(args[1]->IsObject(), "1st param to update has to be an object")
+        argumentCheck(args[2]->IsObject(), "2nd param to update has to be an object")
+
+        verify(scope->MongoFT()->HasInstance(args.This()));
+
+        if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) {
+            return v8AssertionException("js db in read only mode");
+        }
+
+        DBClientBase * conn = getConnection(scope, args);
+        const string ns = toSTLString(args[0]);
+
+        v8::Handle<v8::Object> q = args[1]->ToObject();
+        v8::Handle<v8::Object> o = args[2]->ToObject();
+
+        bool upsert = args.Length() > 3 && args[3]->IsBoolean() && args[3]->ToBoolean()->Value();
+        bool multi  = args.Length() > 4 && args[4]->IsBoolean() && args[4]->ToBoolean()->Value();
+
+        BSONObj q1 = scope->v8ToMongo(q);
+        BSONObj o1 = scope->v8ToMongo(o);
+        conn->update(ns, q1, o1, upsert, multi);
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> mongoAuth(V8Scope* scope, const v8::Arguments& args) {
+        DBClientWithCommands* conn = getConnection(scope, args);
+        if (NULL == conn)
+            return v8AssertionException("no connection");
+
+        BSONObj params;
+        switch (args.Length()) {
+        case 1:
+            params = scope->v8ToMongo(args[0]->ToObject());
+            break;
+        case 3:
+            params = BSON(saslCommandMechanismFieldName << "MONGODB-CR" <<
+                          saslCommandPrincipalSourceFieldName << toSTLString(args[0]) <<
+                          saslCommandPrincipalFieldName << toSTLString(args[1]) <<
+                          saslCommandPasswordFieldName << toSTLString(args[2]));
+            break;
+        default:
+            return v8AssertionException("mongoAuth takes 1 object or 3 string arguments");
+        }
+        try {
+            conn->auth(params);
+        }
+        catch (const DBException& ex) {
+            return v8AssertionException(ex.toString());
+        }
+        return v8::Boolean::New(true);
+    }
+
+    v8::Handle<v8::Value> mongoLogout(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 1, "logout needs 1 arg")
+        DBClientBase* conn = getConnection(scope, args);
+        const string db = toSTLString(args[0]);
+        BSONObj ret;
+        conn->logout(db, ret);
+        return scope->mongoToLZV8(ret, false);
+    }
+
+    /**
+     * get cursor from v8 argument
+     */
+    mongo::DBClientCursor* getCursor(V8Scope* scope, const v8::Arguments& args) {
+        verify(scope->InternalCursorFT()->HasInstance(args.This()));
+        verify(args.This()->InternalFieldCount() == 1);
+        v8::Local<v8::External> c = v8::External::Cast(*(args.This()->GetInternalField(0)));
+        mongo::DBClientCursor* cursor = static_cast<mongo::DBClientCursor*>(c->Value());
+        return cursor;
+    }
+
+    v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Arguments& args) {
+        return v8::Undefined();
+    }
+
+    /**
+     * cursor.next()
+     */
+    v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Arguments& args) {
+        mongo::DBClientCursor* cursor = getCursor(scope, args);
+        if (! cursor)
+            return v8::Undefined();
+        BSONObj o = cursor->next();
+        bool ro = false;
+        if (args.This()->Has(v8::String::New("_ro")))
+            ro = args.This()->Get(v8::String::New("_ro"))->BooleanValue();
+        return scope->mongoToLZV8(o, ro);
+    }
+
+    /**
+     * cursor.hasNext()
+     */
+    v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args) {
+        mongo::DBClientCursor* cursor = getCursor(scope, args);
+        if (! cursor)
+            return v8::Boolean::New(false);
+        return v8::Boolean::New(cursor->more());
+    }
+
+    /**
+     * cursor.objsLeftInBatch()
+     */
+    v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope,
+                                                        const v8::Arguments& args) {
+        mongo::DBClientCursor* cursor = getCursor(scope, args);
+        if (! cursor)
+            return v8::Number::New(0.0);
+        return v8::Number::New(static_cast<double>(cursor->objsLeftInBatch()));
+    }
+
+    /**
+     * cursor.readOnly()
+     */
+    v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8::Arguments& args) {
+        verify(scope->InternalCursorFT()->HasInstance(args.This()));
+
+        v8::Local<v8::Object> cursor = args.This();
+        cursor->ForceSet(v8::String::New("_ro"), v8::Boolean::New(true));
+        return cursor;
+    }
+
+    v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->DBFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        verify(scope->DBFT()->HasInstance(args.This()));
+
+        argumentCheck(args.Length() == 2, "db constructor requires 2 arguments")
+
+        args.This()->ForceSet(scope->v8StringData("_mongo"), args[0]);
+        args.This()->ForceSet(scope->v8StringData("_name"), args[1]);
+
+        for (int i = 0; i < args.Length(); i++) {
+            argumentCheck(!args[i]->IsUndefined(), "db initializer called with undefined argument")
+        }
+
+        string dbName = toSTLString(args[1]);
+        if (!NamespaceString::validDBName(dbName)) {
+            return v8AssertionException(str::stream() << "[" << dbName
+                                                      << "] is not a valid database name");
+        }
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->DBCollectionFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        verify(scope->DBCollectionFT()->HasInstance(args.This()));
+
+        argumentCheck(args.Length() == 4, "collection constructor requires 4 arguments")
+
+        for (int i = 0; i < args.Length(); i++) {
+            argumentCheck(!args[i]->IsUndefined(),
+                          "collection constructor called with undefined argument")
+        }
+
+        args.This()->ForceSet(scope->v8StringData("_mongo"), args[0]);
+        args.This()->ForceSet(scope->v8StringData("_db"), args[1]);
+        args.This()->ForceSet(scope->v8StringData("_shortName"), args[2]);
+        args.This()->ForceSet(v8::String::New("_fullName"), args[3]);
+
+        if (haveLocalShardingInfo(toSTLString(args[3]))) {
+            return v8AssertionException("can't use sharded collection from db.eval");
+        }
+
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> dbQueryInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->DBQueryFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        verify(scope->DBQueryFT()->HasInstance(args.This()));
+
+        argumentCheck(args.Length() >= 4, "dbQuery constructor requires at least 4 arguments")
+
+        v8::Handle<v8::Object> t = args.This();
+        t->ForceSet(scope->v8StringData("_mongo"), args[0]);
+        t->ForceSet(scope->v8StringData("_db"), args[1]);
+        t->ForceSet(scope->v8StringData("_collection"), args[2]);
+        t->ForceSet(scope->v8StringData("_ns"), args[3]);
+
+        if (args.Length() > 4 && args[4]->IsObject())
+            t->ForceSet(scope->v8StringData("_query"), args[4]);
+        else
+            t->ForceSet(scope->v8StringData("_query"), v8::Object::New());
+
+        if (args.Length() > 5 && args[5]->IsObject())
+            t->ForceSet(scope->v8StringData("_fields"), args[5]);
+        else
+            t->ForceSet(scope->v8StringData("_fields"), v8::Null());
+
+        if (args.Length() > 6 && args[6]->IsNumber())
+            t->ForceSet(scope->v8StringData("_limit"), args[6]);
+        else
+            t->ForceSet(scope->v8StringData("_limit"), v8::Number::New(0));
+
+        if (args.Length() > 7 && args[7]->IsNumber())
+            t->ForceSet(scope->v8StringData("_skip"), args[7]);
+        else
+            t->ForceSet(scope->v8StringData("_skip"), v8::Number::New(0));
+
+        if (args.Length() > 8 && args[8]->IsNumber())
+            t->ForceSet(scope->v8StringData("_batchSize"), args[8]);
+        else
+            t->ForceSet(scope->v8StringData("_batchSize"), v8::Number::New(0));
+
+        if (args.Length() > 9 && args[9]->IsNumber())
+            t->ForceSet(scope->v8StringData("_options"), args[9]);
+        else
+            t->ForceSet(scope->v8StringData("_options"), v8::Number::New(0));
+
+        t->ForceSet(scope->v8StringData("_cursor"), v8::Null());
+        t->ForceSet(scope->v8StringData("_numReturned"), v8::Number::New(0));
+        t->ForceSet(scope->v8StringData("_special"), v8::Boolean::New(false));
+
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> collectionSetter(v8::Local<v8::String> name,
+                                           v8::Local<v8::Value> value,
+                                           const v8::AccessorInfo& info) {
+        try {
+            V8Scope* scope = getScope(info.GetIsolate());
+
+            // Both DB and Collection objects use this setter
+            verify(scope->DBCollectionFT()->HasInstance(info.This())
+                || scope->DBFT()->HasInstance(info.This()));
+
+            // a collection name cannot be overwritten by a variable
+            string sname = toSTLString(name);
+            if (sname.length() == 0 || sname[0] == '_') {
+                // if starts with '_' we allow overwrite
+                return v8::Handle<v8::Value>();
+            }
+            // dont set
+            return value;
+        }
+        catch (const DBException& dbEx) {
+            return v8AssertionException(dbEx.toString());
+        }
+        catch (...) {
+            return v8AssertionException("unknown error in collationSetter");
+        }
+    }
+
+    v8::Handle<v8::Value> collectionGetter(v8::Local<v8::String> name,
+                                           const v8::AccessorInfo& info) {
+        try {
+            V8Scope* scope = getScope(info.GetIsolate());
+
+            // Both DB and Collection objects use this getter
+            verify(scope->DBCollectionFT()->HasInstance(info.This())
+                || scope->DBFT()->HasInstance(info.This()));
+
+            v8::TryCatch tryCatch;
+
+            // first look in prototype, may be a function
+            v8::Handle<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get(name);
+            if (!real->IsUndefined())
+                return real;
+
+            // 2nd look into real values, may be cached collection object
+            string sname = toSTLString(name);
+            if (info.This()->HasRealNamedProperty(name)) {
+                v8::Local<v8::Value> prop = info.This()->GetRealNamedProperty(name);
+                if (prop->IsObject() &&
+                    prop->ToObject()->HasRealNamedProperty(v8::String::New("_fullName"))) {
+                    // need to check every time that the collection did not get sharded
+                    if (haveLocalShardingInfo(toSTLString(
+                            prop->ToObject()->GetRealNamedProperty(v8::String::New("_fullName"))))) {
+                        return v8AssertionException("can't use sharded collection from db.eval");
+                    }
+                }
+                return prop;
+            }
+            else if (sname.length() == 0 || sname[0] == '_') {
+                // if starts with '_' we dont return collection, one must use getCollection()
+                return v8::Handle<v8::Value>();
+            }
+
+            // no hit, create new collection
+            v8::Handle<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get(
+                    v8::String::New("getCollection"));
+            if (! getCollection->IsFunction()) {
+                return v8AssertionException("getCollection is not a function");
+            }
+
+            v8::Handle<v8::Function> f = getCollection.As<v8::Function>();
+            v8::Handle<v8::Value> argv[1];
+            argv[0] = name;
+            v8::Local<v8::Value> coll = f->Call(info.This(), 1, argv);
+            if (coll.IsEmpty())
+                return tryCatch.ReThrow();
+
+            uassert(16861, "getCollection returned something other than a collection",
+                    scope->DBCollectionFT()->HasInstance(coll));
+
+            // cache collection for reuse, don't enumerate
+            info.This()->ForceSet(name, coll, v8::DontEnum);
+            return coll;
+        }
+        catch (const DBException& dbEx) {
+            return v8AssertionException(dbEx.toString());
+        }
+        catch (...) {
+            return v8AssertionException("unknown error in collectionGetter");
+        }
+    }
+
+    v8::Handle<v8::Value> dbQueryIndexAccess(unsigned int index, const v8::AccessorInfo& info) {
+        try {
+            V8Scope* scope = getScope(info.GetIsolate());
+            verify(scope->DBQueryFT()->HasInstance(info.This()));
+
+            v8::Handle<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get(
+                    v8::String::New("arrayAccess"));
+            massert(16660, "arrayAccess is not a function", arrayAccess->IsFunction());
+
+            v8::Handle<v8::Function> f = arrayAccess.As<v8::Function>();
+            v8::Handle<v8::Value> argv[1];
+            argv[0] = v8::Number::New(index);
+
+            return f->Call(info.This(), 1, argv);
+        }
+        catch (const DBException& dbEx) {
+            return v8AssertionException(dbEx.toString());
+        }
+        catch (...) {
+            return v8AssertionException("unknown error in dbQueryIndexAccess");
+        }
+    }
+
+    v8::Handle<v8::Value> objectIdInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->ObjectIdFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->ObjectIdFT()->HasInstance(it));
+
+        OID oid;
+        if (args.Length() == 0) {
+            oid.init();
+        }
+        else {
+            string s = toSTLString(args[0]);
+            try {
+                Scope::validateObjectIdString(s);
+            }
+            catch (const MsgAssertionException& m) {
+                return v8AssertionException(m.toString());
+            }
+            oid.init(s);
+        }
+
+        it->ForceSet(scope->v8StringData("str"), v8::String::New(oid.str().c_str()));
+        return it;
+    }
+
+    v8::Handle<v8::Value> dbRefInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->DBRefFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->DBRefFT()->HasInstance(it));
+
+        argumentCheck(args.Length() == 2, "DBRef needs 2 arguments")
+        argumentCheck(args[0]->IsString(), "DBRef 1st parameter must be a string")
+        it->ForceSet(scope->v8StringData("$ref"), args[0]);
+        it->ForceSet(scope->v8StringData("$id"),  args[1]);
+        return it;
+    }
+
+    v8::Handle<v8::Value> dbPointerInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->DBPointerFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->DBPointerFT()->HasInstance(it));
+
+        argumentCheck(args.Length() == 2, "DBPointer needs 2 arguments")
+        argumentCheck(args[0]->IsString(), "DBPointer 1st parameter must be a string")
+        argumentCheck(scope->ObjectIdFT()->HasInstance(args[1]),
+                      "DBPointer 2nd parameter must be an ObjectId")
+
+        it->ForceSet(scope->v8StringData("ns"), args[0]);
+        it->ForceSet(scope->v8StringData("id"), args[1]);
+        return it;
+    }
+
+    v8::Handle<v8::Value> dbTimestampInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->TimestampFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->TimestampFT()->HasInstance(it));
+
+        if (args.Length() == 0) {
+            it->ForceSet(scope->v8StringData("t"), v8::Number::New(0));
+            it->ForceSet(scope->v8StringData("i"), v8::Number::New(0));
+        }
+        else if (args.Length() == 2) {
+            if (!args[0]->IsNumber()) {
+                return v8AssertionException("Timestamp time must be a number");
+            }
+            if (!args[1]->IsNumber()) {
+                return v8AssertionException("Timestamp increment must be a number");
+            }
+            int64_t t = args[0]->IntegerValue();
+            int64_t largestVal = ((2039LL-1970LL) *365*24*60*60); //seconds between 1970-2038
+            if( t > largestVal )
+                return v8AssertionException( str::stream()
+                        << "The first argument must be in seconds; "
+                        << t << " is too large (max " << largestVal << ")");
+            it->ForceSet(scope->v8StringData("t"), args[0]);
+            it->ForceSet(scope->v8StringData("i"), args[1]);
+        }
+        else {
+            return v8AssertionException("Timestamp needs 0 or 2 arguments");
+        }
+
+        return it;
+    }
+
+    v8::Handle<v8::Value> binDataInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        v8::Local<v8::Object> it = args.This();
+        verify(scope->BinDataFT()->HasInstance(it));
+
+        if (args.Length() == 2) {
+            // 2 args: type, base64 string
+            v8::Handle<v8::Value> type = args[0];
+            if (!type->IsNumber() || type->Int32Value() < 0 || type->Int32Value() > 255) {
+                return v8AssertionException(
+                        "BinData subtype must be a Number between 0 and 255 inclusive)");
+            }
+            v8::String::Utf8Value utf(args[1]);
+            // uassert if invalid base64 string
+            string tmpBase64 = base64::decode(*utf);
+            // length property stores the decoded length
+            it->ForceSet(scope->v8StringData("len"), v8::Number::New(tmpBase64.length()));
+            it->ForceSet(scope->v8StringData("type"), type);
+            it->SetInternalField(0, args[1]);
+        }
+        else if (args.Length() != 0) {
+            return v8AssertionException("BinData takes 2 arguments -- BinData(subtype,data)");
+        }
+
+        return it;
+    }
+
+    v8::Handle<v8::Value> binDataToString(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->BinDataFT()->HasInstance(it));
+        int type = it->Get(v8::String::New("type"))->Int32Value();
+
+        stringstream ss;
+        verify(it->InternalFieldCount() == 1);
+        ss << "BinData(" << type << ",\"" << toSTLString(it->GetInternalField(0)) << "\")";
+        return v8::String::New(ss.str().c_str());
+    }
+
+    v8::Handle<v8::Value> binDataToBase64(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->BinDataFT()->HasInstance(it));
+        verify(it->InternalFieldCount() == 1);
+        return it->GetInternalField(0);
+    }
+
+    v8::Handle<v8::Value> binDataToHex(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->BinDataFT()->HasInstance(it));
+        int len = v8::Handle<v8::Number>::Cast(it->Get(v8::String::New("len")))->Int32Value();
+        verify(it->InternalFieldCount() == 1);
+        string data = base64::decode(toSTLString(it->GetInternalField(0)));
+        stringstream ss;
+        ss.setf (ios_base::hex, ios_base::basefield);
+        ss.fill ('0');
+        ss.setf (ios_base::right, ios_base::adjustfield);
+        for(int i = 0; i < len; i++) {
+            unsigned v = (unsigned char) data[i];
+            ss << setw(2) << v;
+        }
+        return v8::String::New(ss.str().c_str());
+    }
+
+    static v8::Handle<v8::Value> hexToBinData(V8Scope* scope, v8::Local<v8::Object> it, int type,
+                                              string hexstr) {
+        verify(scope->BinDataFT()->HasInstance(it));
+
+        int len = hexstr.length() / 2;
+        scoped_array<char> data(new char[len]);
+        const char* src = hexstr.c_str();
+        for(int i = 0; i < len; i++) {
+            data[i] = fromHex(src + i * 2);
+        }
+
+        string encoded = base64::encode(data.get(), len);
+        it->ForceSet(v8::String::New("len"), v8::Number::New(len));
+        it->ForceSet(v8::String::New("type"), v8::Number::New(type));
+        it->SetInternalField(0, v8::String::New(encoded.c_str(), encoded.length()));
+        return it;
+    }
+
+    v8::Handle<v8::Value> uuidInit(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 1, "UUID needs 1 argument")
+        v8::String::Utf8Value utf(args[0]);
+        argumentCheck(utf.length() == 32, "UUID string must have 32 characters")
+
+        v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
+        v8::Local<v8::Object> it = f->NewInstance();
+        return hexToBinData(scope, it, bdtUUID, *utf);
+    }
+
+    v8::Handle<v8::Value> md5Init(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 1, "MD5 needs 1 argument")
+        v8::String::Utf8Value utf(args[0]);
+        argumentCheck(utf.length() == 32, "MD5 string must have 32 characters")
+
+        v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
+        v8::Local<v8::Object> it = f->NewInstance();
+        return hexToBinData(scope, it, MD5Type, *utf);
+    }
+
+    v8::Handle<v8::Value> hexDataInit(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 2, "HexData needs 2 arguments")
+        v8::String::Utf8Value utf(args[1]);
+        v8::Handle<v8::Function> f = scope->BinDataFT()->GetFunction();
+        v8::Local<v8::Object> it = f->NewInstance();
+        return hexToBinData(scope, it, args[0]->IntegerValue(), *utf);
+    }
+
+    v8::Handle<v8::Value> numberLongInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->NumberLongFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        argumentCheck(args.Length() == 0 || args.Length() == 1 || args.Length() == 3,
+                      "NumberLong needs 0, 1 or 3 arguments")
+
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->NumberLongFT()->HasInstance(it));
+
+        if (args.Length() == 0) {
+            it->ForceSet(scope->v8StringData("floatApprox"), v8::Number::New(0));
+        }
+        else if (args.Length() == 1) {
+            if (args[0]->IsNumber()) {
+                it->ForceSet(scope->v8StringData("floatApprox"), args[0]);
+            }
+            else {
+                v8::String::Utf8Value data(args[0]);
+                string num = *data;
+                const char *numStr = num.c_str();
+                long long n;
+                try {
+                    n = parseLL(numStr);
+                }
+                catch (const AssertionException&) {
+                    return v8AssertionException(string("could not convert \"") +
+                                                num +
+                                                "\" to NumberLong");
+                }
+                unsigned long long val = n;
+                // values above 2^53 are not accurately represented in JS
+                if ((long long)val ==
+                    (long long)(double)(long long)(val) && val < 9007199254740992ULL) {
+                    it->ForceSet(scope->v8StringData("floatApprox"),
+                            v8::Number::New((double)(long long)(val)));
+                }
+                else {
+                    it->ForceSet(scope->v8StringData("floatApprox"),
+                            v8::Number::New((double)(long long)(val)));
+                    it->ForceSet(scope->v8StringData("top"), v8::Integer::New(val >> 32));
+                    it->ForceSet(scope->v8StringData("bottom"),
+                            v8::Integer::New((unsigned long)(val & 0x00000000ffffffff)));
+                }
+            }
+        }
+        else {
+            it->ForceSet(scope->v8StringData("floatApprox"), args[0]->ToNumber());
+            it->ForceSet(scope->v8StringData("top"), args[1]->ToUint32());
+            it->ForceSet(scope->v8StringData("bottom"), args[2]->ToUint32());
+        }
+        return it;
+    }
+
+    long long numberLongVal(V8Scope* scope, const v8::Handle<v8::Object>& it) {
+        verify(scope->NumberLongFT()->HasInstance(it));
+        if (!it->Has(v8::String::New("top")))
+            return (long long)(it->Get(v8::String::New("floatApprox"))->NumberValue());
+        return
+            (long long)
+            ((unsigned long long)(it->Get(v8::String::New("top"))->ToInt32()->Value()) << 32) +
+            (unsigned)(it->Get(v8::String::New("bottom"))->ToInt32()->Value());
+    }
+
+    v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        long long val = numberLongVal(scope, it);
+        return v8::Number::New(double(val));
+    }
+
+    v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Arguments& args) {
+        return numberLongValueOf(scope, args);
+    }
+
+    v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+
+        stringstream ss;
+        long long val = numberLongVal(scope, it);
+        const long long limit = 2LL << 30;
+
+        if (val <= -limit || limit <= val)
+            ss << "NumberLong(\"" << val << "\")";
+        else
+            ss << "NumberLong(" << val << ")";
+
+        string ret = ss.str();
+        return v8::String::New(ret.c_str());
+    }
+
+    v8::Handle<v8::Value> numberIntInit(V8Scope* scope, const v8::Arguments& args) {
+        if (!args.IsConstructCall()) {
+            v8::Handle<v8::Function> f = scope->NumberIntFT()->GetFunction();
+            return newInstance(f, args);
+        }
+
+        v8::Handle<v8::Object> it = args.This();
+        verify(scope->NumberIntFT()->HasInstance(it));
+
+        argumentCheck(args.Length() == 0 || args.Length() == 1, "NumberInt needs 0 or 1 arguments")
+        if (args.Length() == 0) {
+            it->SetHiddenValue(v8::String::New("__NumberInt"), v8::Number::New(0));
+        }
+        else if (args.Length() == 1) {
+            it->SetHiddenValue(v8::String::New("__NumberInt"), args[0]->ToInt32());
+        }
+        return it;
+    }
+
+    int numberIntVal(V8Scope* scope, const v8::Handle<v8::Object>& it) {
+        verify(scope->NumberIntFT()->HasInstance(it));
+        v8::Handle<v8::Value> value = it->GetHiddenValue(v8::String::New("__NumberInt"));
+        verify(!value.IsEmpty());
+        return value->Int32Value();
+    }
+
+    v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        return v8::Integer::New(numberIntVal(scope, it));
+    }
+
+    v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Arguments& args) {
+        return numberIntValueOf(scope, args);
+    }
+
+    v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        int val = numberIntVal(scope, it);
+        string ret = str::stream() << "NumberInt(" << val << ")";
+        return v8::String::New(ret.c_str());
+    }
+
+    v8::Handle<v8::Value> bsonsize(V8Scope* scope, const v8::Arguments& args) {
+        argumentCheck(args.Length() == 1, "bsonsize needs 1 argument")
+        if (args[0]->IsNull()) {
+            return v8::Number::New(0);
+        }
+        argumentCheck(args[0]->IsObject(), "argument to bsonsize has to be an object")
+        return v8::Number::New(scope->v8ToMongo(args[0]->ToObject()).objsize());
+    }
+
+}
Index: mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_db.h
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_db.h
@@ -0,0 +1,122 @@
+// v8_db.h
+
+/*    Copyright 2009 10gen Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <boost/function.hpp>
+#include <v8.h>
+
+#include "mongo/scripting/engine_v8-3.14.h"
+
+namespace mongo {
+
+    class DBClientBase;
+
+    /**
+     * get the DBClientBase connection from JS args
+     */
+    mongo::DBClientBase* getConnection(V8Scope* scope, const v8::Arguments& args);
+
+    // Internal Cursor
+    v8::Handle<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope);
+
+    // Mongo constructors
+    v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scope, bool local);
+
+    // Mongo member functions
+    v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> mongoAuth(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> mongoLogout(V8Scope* scope, const v8::Arguments& args);
+
+    // Cursor object
+    v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8::Arguments& args);
+
+    // BinData object
+    v8::Handle<v8::Value> binDataInit(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> binDataToString(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> binDataToBase64(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> binDataToHex(V8Scope* scope, const v8::Arguments& args);
+
+    // NumberLong object
+    long long numberLongVal(V8Scope* scope, const v8::Handle<v8::Object>& it);
+    v8::Handle<v8::Value> numberLongInit(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Arguments& args);
+
+    // NumberInt object
+    int numberIntVal(V8Scope* scope, const v8::Handle<v8::Object>& it);
+    v8::Handle<v8::Value> numberIntInit(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Arguments& args);
+
+    // DBQuery object
+    v8::Handle<v8::Value> dbQueryInit(V8Scope* scope, const v8::Arguments& args);
+    v8::Handle<v8::Value> dbQueryIndexAccess(::uint32_t index, const v8::AccessorInfo& info);
+
+    // db constructor
+    v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args);
+
+    // collection constructor
+    v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Arguments& args);
+
+    // ObjectId constructor
+    v8::Handle<v8::Value> objectIdInit(V8Scope* scope, const v8::Arguments& args);
+
+    // DBRef constructor
+    v8::Handle<v8::Value> dbRefInit(V8Scope* scope, const v8::Arguments& args);
+
+    // DBPointer constructor
+    v8::Handle<v8::Value> dbPointerInit(V8Scope* scope, const v8::Arguments& args);
+
+    // Timestamp constructor
+    v8::Handle<v8::Value> dbTimestampInit(V8Scope* scope, const v8::Arguments& args);
+
+    // UUID constructor
+    v8::Handle<v8::Value> uuidInit(V8Scope* scope, const v8::Arguments& args);
+
+    // MD5 constructor
+    v8::Handle<v8::Value> md5Init(V8Scope* scope, const v8::Arguments& args);
+
+    // HexData constructor
+    v8::Handle<v8::Value> hexDataInit(V8Scope* scope, const v8::Arguments& args);
+
+    // Object.bsonsize()
+    v8::Handle<v8::Value> bsonsize(V8Scope* scope, const v8::Arguments& args);
+
+    // 'db.collection' property handlers
+    v8::Handle<v8::Value> collectionGetter(v8::Local<v8::String> name,
+                                           const v8::AccessorInfo& info);
+    v8::Handle<v8::Value> collectionSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value,
+                                           const v8::AccessorInfo& info);
+
+    typedef boost::function<void (V8Scope*, const v8::Handle<v8::FunctionTemplate>&)>
+            V8FunctionPrototypeManipulatorFn;
+
+    void v8RegisterMongoPrototypeManipulator(const V8FunctionPrototypeManipulatorFn& manipulator);
+}
+
Index: mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_profiler.cpp
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_profiler.cpp
@@ -0,0 +1,65 @@
+/*    Copyright 2013 10gen 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/>.
+ */
+
+#include "mongo/scripting/v8-3.14_profiler.h"
+
+#include "mongo/util/log.h"
+#include "mongo/util/mongoutils/str.h"
+
+namespace mongo {
+    void V8CpuProfiler::start(const StringData name) {
+        v8::CpuProfiler::StartProfiling(v8::String::New(name.toString().c_str()));
+    }
+
+    void V8CpuProfiler::stop(const StringData name) {
+        _cpuProfiles.insert(make_pair(name.toString(),
+                v8::CpuProfiler::StopProfiling(v8::String::New(name.toString().c_str(),
+                                                               name.size()))));
+    }
+
+    void V8CpuProfiler::traverseDepthFirst(const v8::CpuProfileNode* cpuProfileNode,
+                                           BSONArrayBuilder& arrayBuilder) {
+        if (cpuProfileNode == NULL)
+            return;
+        BSONObjBuilder frameObjBuilder;
+        frameObjBuilder.append("Function",
+                               *v8::String::Utf8Value(cpuProfileNode->GetFunctionName()));
+        frameObjBuilder.append("Source",
+                               *v8::String::Utf8Value(cpuProfileNode->GetScriptResourceName()));
+        frameObjBuilder.appendNumber("Line", cpuProfileNode->GetLineNumber());
+        frameObjBuilder.appendNumber("SelfTime", cpuProfileNode->GetSelfTime());
+        frameObjBuilder.appendNumber("TotalTime", cpuProfileNode->GetTotalTime());
+        if (cpuProfileNode->GetChildrenCount()) {
+            BSONArrayBuilder subArrayBuilder(frameObjBuilder.subarrayStart("Children"));
+            for (int i = 0; i < cpuProfileNode->GetChildrenCount(); ++i) {
+                traverseDepthFirst(cpuProfileNode->GetChild(i), subArrayBuilder);
+            }
+            subArrayBuilder.done();
+        }
+        arrayBuilder << frameObjBuilder.obj();
+    }
+
+    const BSONArray V8CpuProfiler::fetch(const StringData name) {
+        BSONArrayBuilder arrayBuilder;
+        CpuProfileMap::const_iterator iProf = _cpuProfiles.find(name.toString());
+        if (iProf == _cpuProfiles.end())
+            return arrayBuilder.arr();
+        const v8::CpuProfile* cpuProfile = iProf->second;
+        if (cpuProfile == NULL)
+            return arrayBuilder.arr();
+        traverseDepthFirst(cpuProfile->GetTopDownRoot(), arrayBuilder);
+        return arrayBuilder.arr();
+    }
+}
Index: mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_profiler.h
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_profiler.h
@@ -0,0 +1,46 @@
+/*    Copyright 2013 10gen Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <v8.h>
+#include <v8-profiler.h>
+#include <map>
+
+#include "mongo/base/string_data.h"
+#include "mongo/db/jsobj.h"
+
+namespace mongo {
+
+    /** Collect CPU Profiling data from v8. */
+    class V8CpuProfiler {
+    public:
+        /** Start the CPU profiler */
+        void start(const StringData name);
+
+        /** Stop the CPU profiler */
+        void stop(const StringData name);
+
+        /** Get the current cpu profile */
+        const BSONArray fetch(const StringData name);
+    private:
+        void traverseDepthFirst(const v8::CpuProfileNode* cpuProfileNode,
+                                BSONArrayBuilder& arrayBuilder);
+
+        typedef std::map<std::string, const v8::CpuProfile*> CpuProfileMap;
+        CpuProfileMap _cpuProfiles;
+    };
+
+}
Index: mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_utils.cpp
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_utils.cpp
@@ -0,0 +1,255 @@
+// v8_utils.cpp
+
+/*    Copyright 2009 10gen 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/>.
+ */
+
+#include "mongo/scripting/v8-3.14_utils.h"
+
+#include <boost/smart_ptr.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <vector>
+
+#include "mongo/platform/cstdint.h"
+#include "mongo/scripting/engine_v8-3.14.h"
+#include "mongo/scripting/v8-3.14_db.h"
+#include "mongo/util/mongoutils/str.h"
+
+using namespace std;
+
+namespace mongo {
+
+    std::string toSTLString(const v8::Handle<v8::Value>& o) {
+        return StringData(V8String(o)).toString();
+    }
+
+    /** Get the properties of an object (and its prototype) as a comma-delimited string */
+    std::string v8ObjectToString(const v8::Handle<v8::Object>& o) {
+        v8::Local<v8::Array> properties = o->GetPropertyNames();
+        v8::String::Utf8Value str(properties);
+        massert(16696 , "error converting js type to Utf8Value", *str);
+        return std::string(*str, str.length());
+    }
+
+    std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::Value>& o) {
+        v8::String::Utf8Value str(o);
+        s << *str;
+        return s;
+    }
+
+    std::ostream& operator<<(std::ostream& s, const v8::TryCatch* try_catch) {
+        v8::HandleScope handle_scope;
+        v8::String::Utf8Value exceptionText(try_catch->Exception());
+        v8::Handle<v8::Message> message = try_catch->Message();
+
+        if (message.IsEmpty()) {
+            s << *exceptionText << endl;
+        }
+        else {
+            v8::String::Utf8Value filename(message->GetScriptResourceName());
+            int linenum = message->GetLineNumber();
+            cout << *filename << ":" << linenum << " " << *exceptionText << endl;
+
+            v8::String::Utf8Value sourceline(message->GetSourceLine());
+            cout << *sourceline << endl;
+
+            int start = message->GetStartColumn();
+            for (int i = 0; i < start; i++)
+                cout << " ";
+
+            int end = message->GetEndColumn();
+            for (int i = start; i < end; i++)
+                cout << "^";
+
+            cout << endl;
+        }
+        return s;
+    }
+
+    class JSThreadConfig {
+    public:
+        JSThreadConfig(V8Scope* scope, const v8::Arguments& args, bool newScope = false) :
+            _started(),
+            _done(),
+            _newScope(newScope) {
+            jsassert(args.Length() > 0, "need at least one argument");
+            jsassert(args[0]->IsFunction(), "first argument must be a function");
+
+            // arguments need to be copied into the isolate, go through bson
+            BSONObjBuilder b;
+            for(int i = 0; i < args.Length(); ++i) {
+                scope->v8ToMongoElement(b, "arg" + BSONObjBuilder::numStr(i), args[i]);
+            }
+            _args = b.obj();
+        }
+
+        ~JSThreadConfig() {
+        }
+
+        void start() {
+            jsassert(!_started, "Thread already started");
+            JSThread jt(*this);
+            _thread.reset(new boost::thread(jt));
+            _started = true;
+        }
+        void join() {
+            jsassert(_started && !_done, "Thread not running");
+            _thread->join();
+            _done = true;
+        }
+
+        BSONObj returnData() {
+            if (!_done)
+                join();
+            return _returnData;
+        }
+
+    private:
+        class JSThread {
+        public:
+            JSThread(JSThreadConfig& config) : _config(config) {}
+
+            void operator()() {
+                _config._scope.reset(static_cast<V8Scope*>(globalScriptEngine->newScope()));
+                v8::Locker v8lock(_config._scope->getIsolate());
+                v8::Isolate::Scope iscope(_config._scope->getIsolate());
+                v8::HandleScope handle_scope;
+                v8::Context::Scope context_scope(_config._scope->getContext());
+
+                BSONObj args = _config._args;
+                v8::Local<v8::Function> f = v8::Function::Cast(
+                        *(_config._scope->mongoToV8Element(args.firstElement(), true)));
+                int argc = args.nFields() - 1;
+
+                // TODO SERVER-8016: properly allocate handles on the stack
+                v8::Local<v8::Value> argv[24];
+                BSONObjIterator it(args);
+                it.next();
+                for(int i = 0; i < argc && i < 24; ++i) {
+                    argv[i] = v8::Local<v8::Value>::New(
+                            _config._scope->mongoToV8Element(*it, true));
+                    it.next();
+                }
+                v8::TryCatch try_catch;
+                v8::Handle<v8::Value> ret =
+                        f->Call(_config._scope->getContext()->Global(), argc, argv);
+                if (ret.IsEmpty() || try_catch.HasCaught()) {
+                    string e = _config._scope->v8ExceptionToSTLString(&try_catch);
+                    log() << "js thread raised exception: " << e << endl;
+                    ret = v8::Undefined();
+                }
+                // ret is translated to BSON to switch isolate
+                BSONObjBuilder b;
+                _config._scope->v8ToMongoElement(b, "ret", ret);
+                _config._returnData = b.obj();
+            }
+
+        private:
+            JSThreadConfig& _config;
+        };
+
+        bool _started;
+        bool _done;
+        bool _newScope;
+        BSONObj _args;
+        scoped_ptr<boost::thread> _thread;
+        scoped_ptr<V8Scope> _scope;
+        BSONObj _returnData;
+    };
+
+    v8::Handle<v8::Value> ThreadInit(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        // NOTE I believe the passed JSThreadConfig will never be freed.  If this
+        // policy is changed, JSThread may no longer be able to store JSThreadConfig
+        // by reference.
+        it->SetHiddenValue(v8::String::New("_JSThreadConfig"),
+                           v8::External::New(new JSThreadConfig(scope, args)));
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> ScopedThreadInit(V8Scope* scope, const v8::Arguments& args) {
+        v8::Handle<v8::Object> it = args.This();
+        // NOTE I believe the passed JSThreadConfig will never be freed.  If this
+        // policy is changed, JSThread may no longer be able to store JSThreadConfig
+        // by reference.
+        it->SetHiddenValue(v8::String::New("_JSThreadConfig"),
+                           v8::External::New(new JSThreadConfig(scope, args, true)));
+        return v8::Undefined();
+    }
+
+    JSThreadConfig *thisConfig(V8Scope* scope, const v8::Arguments& args) {
+        v8::Local<v8::External> c = v8::External::Cast(
+                *(args.This()->GetHiddenValue(v8::String::New("_JSThreadConfig"))));
+        JSThreadConfig *config = (JSThreadConfig *)(c->Value());
+        return config;
+    }
+
+    v8::Handle<v8::Value> ThreadStart(V8Scope* scope, const v8::Arguments& args) {
+        thisConfig(scope, args)->start();
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> ThreadJoin(V8Scope* scope, const v8::Arguments& args) {
+        thisConfig(scope, args)->join();
+        return v8::Undefined();
+    }
+
+    v8::Handle<v8::Value> ThreadReturnData(V8Scope* scope, const v8::Arguments& args) {
+        BSONObj data = thisConfig(scope, args)->returnData();
+        return scope->mongoToV8Element(data.firstElement(), true);
+    }
+
+    v8::Handle<v8::Value> ThreadInject(V8Scope* scope, const v8::Arguments& args) {
+        v8::HandleScope handle_scope;
+        jsassert(args.Length() == 1, "threadInject takes exactly 1 argument");
+        jsassert(args[0]->IsObject(), "threadInject needs to be passed a prototype");
+        v8::Local<v8::Object> o = args[0]->ToObject();
+
+        // install method on the Thread object
+        scope->injectV8Function("init", ThreadInit, o);
+        scope->injectV8Function("start", ThreadStart, o);
+        scope->injectV8Function("join", ThreadJoin, o);
+        scope->injectV8Function("returnData", ThreadReturnData, o);
+        return handle_scope.Close(v8::Handle<v8::Value>());
+    }
+
+    v8::Handle<v8::Value> ScopedThreadInject(V8Scope* scope, const v8::Arguments& args) {
+        v8::HandleScope handle_scope;
+        jsassert(args.Length() == 1, "threadInject takes exactly 1 argument");
+        jsassert(args[0]->IsObject(), "threadInject needs to be passed a prototype");
+        v8::Local<v8::Object> o = args[0]->ToObject();
+
+        scope->injectV8Function("init", ScopedThreadInit, o);
+        // inheritance takes care of other member functions
+
+        return handle_scope.Close(v8::Handle<v8::Value>());
+    }
+
+    void installFork(V8Scope* scope, v8::Handle<v8::Object>& global,
+                     v8::Handle<v8::Context>& context) {
+        scope->injectV8Function("_threadInject", ThreadInject, global);
+        scope->injectV8Function("_scopedThreadInject", ScopedThreadInject, global);
+    }
+
+    v8::Handle<v8::Value> v8AssertionException(const char* errorMessage) {
+        return v8::ThrowException(v8::Exception::Error(v8::String::New(errorMessage)));
+    }
+    v8::Handle<v8::Value> v8AssertionException(const std::string& errorMessage) {
+        return v8AssertionException(errorMessage.c_str());
+    }
+}
Index: mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_utils.h
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/mongo/scripting/v8-3.14_utils.h
@@ -0,0 +1,106 @@
+// v8_utils.h
+
+/*    Copyright 2009 10gen Inc.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#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))
+
+#define argumentCheck(mustBeTrue, errorMessage)         \
+    if (!(mustBeTrue)) {                                \
+        return v8AssertionException((errorMessage));    \
+    }
+
+    std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::Value>& o);
+    std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::TryCatch>* try_catch);
+
+    /** 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);
+
+    class V8Scope;
+    void installFork(V8Scope* scope,
+                     v8::Handle<v8::Object>& global,
+                     v8::Handle<v8::Context>& context);
+
+    /** Throw a V8 exception from Mongo callback code; message text will be preceded by "Error: ".
+     *   Note: this function should be used for text that did not originate from the JavaScript
+     *         engine.  Errors from the JavaScript engine will already have a prefix such as
+     *         ReferenceError, TypeError or SyntaxError.
+     *   Note: call only from a native function called from JavaScript (a callback).
+     *         The V8 ThrowException routine will note a JavaScript exception that will be
+     *         "thrown" in JavaScript when we return from the native function.
+     *   Note: it's required to return immediately to V8's execution control without calling any
+     *         V8 API functions.  In this state, an empty handle may (will) be returned.
+     *  @param   errorMessage Error message text.
+     *  @return  Empty handle to be returned from callback function.
+     */
+    v8::Handle<v8::Value> v8AssertionException(const char* errorMessage);
+    v8::Handle<v8::Value> v8AssertionException(const std::string& errorMessage);
+}
+
Index: mongodb-src-r2.4.10/src/third_party/SConscript
===================================================================
--- mongodb-src-r2.4.10.orig/src/third_party/SConscript
+++ mongodb-src-r2.4.10/src/third_party/SConscript
@@ -1,6 +1,6 @@
 # -*- mode: python -*-
 
-Import("env use_system_version_of_library windows darwin usesm usev8")
+Import("env use_system_version_of_library windows darwin usesm usev8 v8suffix")
 
 env.SConscript( [
         "murmurhash3/SConscript",
@@ -49,9 +49,9 @@ elif usev8:
     if use_system_version_of_library("v8"):
         env.StaticLibrary("shim_v8", ['shim_v8.cpp'], SYSLIBDEPS=['v8'])
     else:
-        env.Append(CPPPATH='$BUILD_DIR/third_party/v8/include')
-        env.SConscript('v8/SConscript')
-        env.StaticLibrary('shim_v8', ['shim_v8.cpp'], LIBDEPS=['v8/v8'])
+        env.Append(CPPPATH='$BUILD_DIR/third_party/v8' + v8suffix + '/include')
+        env.SConscript('v8' + v8suffix + '/SConscript')
+        env.StaticLibrary('shim_v8', ['shim_v8.cpp'], LIBDEPS=['v8' + v8suffix + '/v8'])
 
 if (GetOption("allocator") != "tcmalloc") or use_system_version_of_library("tcmalloc"):
     env.StaticLibrary("shim_allocator", "shim_allocator.cpp")
Index: mongodb-src-r2.4.10/src/third_party/v8-3.14/SConscript
===================================================================
--- /dev/null
+++ mongodb-src-r2.4.10/src/third_party/v8-3.14/SConscript
@@ -0,0 +1,396 @@
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# set up path for js2c import
+import sys
+from os.path import join, dirname, abspath
+root_dir = dirname(File('SConscript').rfile().abspath)
+sys.path.append(join(root_dir, 'tools'))
+import js2c
+
+Import("env windows linux darwin solaris freebsd debugBuild")
+
+# pared-down copies of the equivalent structures in v8's SConstruct/SConscript:
+LIBRARY_FLAGS = {
+  'all': {
+    'all': {
+      'CPPDEFINES':   ['ENABLE_DEBUGGER_SUPPORT', 'VERIFY_HEAP'],
+    },
+    'mode:debug': {
+      'CPPDEFINES':   ['V8_ENABLE_CHECKS', 'OBJECT_PRINT']
+    },
+  },
+  'gcc': {
+    'all': {
+      'CCFLAGS':      ['-Wno-unused-parameter',
+                       '-Woverloaded-virtual',
+                       '-Wnon-virtual-dtor']
+    },
+    'mode:debug': {
+      'CPPDEFINES':   ['ENABLE_DISASSEMBLER', 'DEBUG'],
+    },
+    'os:linux': {
+      'CCFLAGS':      ['-ansi', '-pedantic'],
+    },
+    'os:macos': {
+      'CCFLAGS':      ['-ansi', '-pedantic'],
+    },
+    'os:freebsd': {
+      'CCFLAGS':      ['-ansi'],
+    },
+    'os:solaris': {
+      # On Solaris, to get isinf, INFINITY, fpclassify and other macros one
+      # needs to define __C99FEATURES__.
+      'CPPDEFINES':   ['__C99FEATURES__'],
+      'CCFLAGS':      ['-ansi'],
+    },
+    'arch:ia32': {
+      'CPPDEFINES':   ['V8_TARGET_ARCH_IA32'],
+    },
+    'arch:x64': {
+      'CPPDEFINES':   ['V8_TARGET_ARCH_X64'],
+    },
+  },
+  'msvc': {
+    'all': {
+      'CPPDEFINES':   ['WIN32', '_CRT_RAND_S'],
+      'CCFLAGS':      ['/W3', '/WX', '/wd4351', '/wd4355', '/wd4800'],
+    },
+    'arch:ia32': {
+      'CPPDEFINES':   ['V8_TARGET_ARCH_IA32', '_USE_32BIT_TIME_T', 'V8_NO_FAST_TLS'],
+    },
+    'arch:x64': {
+      'CPPDEFINES':   ['V8_TARGET_ARCH_X64'],
+    },
+    'mode:debug': {
+      'CPPDEFINES':   ['_DEBUG', 'ENABLE_DISASSEMBLER', 'DEBUG'],
+    },
+  }
+}
+
+SOURCES = {
+  'all': Split("""
+    accessors.cc
+    allocation.cc
+    api.cc
+    assembler.cc
+    ast.cc
+    atomicops_internals_x86_gcc.cc
+    bignum-dtoa.cc
+    bignum.cc
+    bootstrapper.cc
+    builtins.cc
+    cached-powers.cc
+    checks.cc
+    circular-queue.cc
+    code-stubs.cc
+    codegen.cc
+    compilation-cache.cc
+    compiler.cc
+    contexts.cc
+    conversions.cc
+    counters.cc
+    cpu-profiler.cc
+    data-flow.cc
+    date.cc
+    dateparser.cc
+    debug-agent.cc
+    debug.cc
+    deoptimizer.cc
+    disassembler.cc
+    diy-fp.cc
+    dtoa.cc
+    elements-kind.cc
+    elements.cc
+    execution.cc
+    extensions/externalize-string-extension.cc
+    extensions/gc-extension.cc
+    extensions/statistics-extension.cc
+    factory.cc
+    fast-dtoa.cc
+    fixed-dtoa.cc
+    flags.cc
+    frames.cc
+    full-codegen.cc
+    func-name-inferrer.cc
+    gdb-jit.cc
+    global-handles.cc
+    handles.cc
+    heap-profiler.cc
+    heap.cc
+    hydrogen-instructions.cc
+    hydrogen.cc
+    ic.cc
+    incremental-marking.cc
+    inspector.cc
+    interface.cc
+    interpreter-irregexp.cc
+    isolate.cc
+    jsregexp.cc
+    lithium-allocator.cc
+    lithium.cc
+    liveedit.cc
+    liveobjectlist.cc
+    log-utils.cc
+    log.cc
+    mark-compact.cc
+    messages.cc
+    objects-printer.cc
+    objects-visiting.cc
+    objects.cc
+    objects-debug.cc
+    once.cc
+    optimizing-compiler-thread.cc
+    parser.cc
+    preparse-data.cc
+    preparser.cc
+    profile-generator.cc
+    property.cc
+    regexp-macro-assembler-irregexp.cc
+    regexp-macro-assembler.cc
+    regexp-stack.cc
+    rewriter.cc
+    runtime-profiler.cc
+    runtime.cc
+    safepoint-table.cc
+    scanner-character-streams.cc
+    scanner.cc
+    scopeinfo.cc
+    scopes.cc
+    serialize.cc
+    snapshot-common.cc
+    spaces.cc
+    store-buffer.cc
+    string-search.cc
+    string-stream.cc
+    strtod.cc
+    stub-cache.cc
+    token.cc
+    transitions.cc
+    type-info.cc
+    unicode.cc
+    utils.cc
+    v8-counters.cc
+    v8.cc
+    v8conversions.cc
+    v8threads.cc
+    v8utils.cc
+    variables.cc
+    version.cc
+    zone.cc
+    """),
+  'arch:ia32': Split("""
+    ia32/assembler-ia32.cc
+    ia32/builtins-ia32.cc
+    ia32/code-stubs-ia32.cc
+    ia32/codegen-ia32.cc
+    ia32/cpu-ia32.cc
+    ia32/debug-ia32.cc
+    ia32/deoptimizer-ia32.cc
+    ia32/disasm-ia32.cc
+    ia32/frames-ia32.cc
+    ia32/full-codegen-ia32.cc
+    ia32/ic-ia32.cc
+    ia32/lithium-codegen-ia32.cc
+    ia32/lithium-gap-resolver-ia32.cc
+    ia32/lithium-ia32.cc
+    ia32/macro-assembler-ia32.cc
+    ia32/regexp-macro-assembler-ia32.cc
+    ia32/stub-cache-ia32.cc
+    """),
+  'arch:x64': Split("""
+    x64/assembler-x64.cc
+    x64/builtins-x64.cc
+    x64/code-stubs-x64.cc
+    x64/codegen-x64.cc
+    x64/cpu-x64.cc
+    x64/debug-x64.cc
+    x64/deoptimizer-x64.cc
+    x64/disasm-x64.cc
+    x64/frames-x64.cc
+    x64/full-codegen-x64.cc
+    x64/ic-x64.cc
+    x64/lithium-codegen-x64.cc
+    x64/lithium-gap-resolver-x64.cc
+    x64/lithium-x64.cc
+    x64/macro-assembler-x64.cc
+    x64/regexp-macro-assembler-x64.cc
+    x64/stub-cache-x64.cc
+    """),
+  'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
+  'os:openbsd': ['platform-openbsd.cc', 'platform-posix.cc'],
+  'os:linux':   ['platform-linux.cc', 'platform-posix.cc'],
+  'os:macos':   ['platform-macos.cc', 'platform-posix.cc'],
+  'os:solaris': ['platform-solaris.cc', 'platform-posix.cc'],
+  'os:nullos':  ['platform-nullos.cc'],
+  'os:win32':   ['platform-win32.cc', 'win32-math.cc'],
+  'mode:release': [],
+  'mode:debug': [
+    'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
+  ]
+}
+
+EXPERIMENTAL_LIBRARY_FILES = '''
+proxy.js
+collection.js
+'''.split()
+
+LIBRARY_FILES = '''
+runtime.js
+v8natives.js
+array.js
+string.js
+uri.js
+math.js
+messages.js
+apinatives.js
+date.js
+regexp.js
+json.js
+liveedit-debugger.js
+mirror-debugger.js
+debug-debugger.js
+'''.split()
+
+def get_flags(flag, toolchain, options):
+    ret = []
+    for t in (toolchain, 'all'):
+        for o in (options.values() + ['all']):
+            ret.extend(LIBRARY_FLAGS[t].get(o,{}).get(flag,[]))
+    return ret
+
+def get_options():
+    processor = env['PROCESSOR_ARCHITECTURE']
+    if processor == 'i386':
+        arch_string = 'arch:ia32'
+    elif processor == 'i686':
+        arch_string = 'arch:ia32'
+    elif processor == 'x86_64':
+        arch_string = 'arch:x64'
+    elif processor == 'amd64':
+        arch_string = 'arch:x64'
+    else:
+        assert False, "Unsupported architecture: " + processor
+
+    if linux:
+        os_string = 'os:linux'
+    elif darwin:
+        os_string = 'os:macos'
+    elif windows:
+        os_string = 'os:win32'
+    elif freebsd:
+        os_string = 'os:freebsd'
+    elif solaris:
+        os_string = 'os:solaris'
+    elif openbsd:
+        os_string = 'os:openbsd'
+    else:
+        os_string = 'os:nullos'
+
+    if debugBuild:
+        mode_string = 'mode:debug'
+    else:
+        mode_string = 'mode:release'
+
+    return {'mode': mode_string, 'os': os_string, 'arch': arch_string}
+
+def get_sources(options):
+    keys = options.values() + ['all']
+
+    sources = []
+    for i in keys:
+        sources.extend(('src/'+s) for s in SOURCES[i])
+
+    # sources generated from .js files:
+    sources.append('src/libraries.cc')
+    sources.append('src/experimental-libraries.cc')
+
+    # we're building with v8 "snapshot=off", which requires this file:
+    sources.append('src/snapshot-empty.cc')
+
+    return sources
+
+def get_toolchain():
+    if windows:
+        return 'msvc'
+    else:
+        return 'gcc'
+
+# convert our SConstruct variables to their v8 equivalents:
+toolchain = get_toolchain()
+options = get_options()
+sources = get_sources(options)
+
+env = env.Clone()
+
+# remove -Iinclude and prepend -Isrc, to resolve namespace conflicts:
+#
+# mongo source needs to compile with include/v8.h, but v8 source
+# needs to compile with src/v8.h
+#
+# in addition, v8 source needs to compile with src/parser.h, which
+# is being placed here earlier in the search path than windows sdk's
+# Include/parser.h (v8 doesn't even use any of those header files)
+env['CPPPATH'].remove('$BUILD_DIR/third_party/v8-3.14/include')
+env.Prepend(CPPPATH='$BUILD_DIR/third_party/v8-3.14/src')
+
+# add v8 ccflags and cppdefines to environment if they're not already
+# present
+ccflags = get_flags('CCFLAGS', toolchain, options)
+ccflags = filter(lambda f :
+                     f not in env['CCFLAGS'] + env['CXXFLAGS'] + env['CFLAGS'],
+                 ccflags)
+env.Append(CCFLAGS=ccflags)
+cppdefines = get_flags('CPPDEFINES', toolchain, options)
+cppdefines = filter(lambda f : f not in env['CPPDEFINES'], cppdefines)
+env.Append(CPPDEFINES=cppdefines)
+
+# NOTE: Suppress attempts to enable warnings in v8. Trying to individually suppress with -Wno-
+# results in a game of whack-a-mole between various versions of clang and gcc as they add new
+# warnings. We won't be changing the v8 sources, so the warnings aren't helpful.
+def removeIfPresent(lst, item):
+    try:
+        lst.remove(item)
+    except ValueError:
+        pass
+
+for to_remove in ['-Werror', '-Wall', '-W']:
+    removeIfPresent(env['CCFLAGS'], to_remove)
+
+# specify rules for building libraries.cc and experimental-libraries.cc
+env['BUILDERS']['JS2C'] = Builder(action=js2c.JS2C)
+experimental_library_files = [('src/'+s) for s in EXPERIMENTAL_LIBRARY_FILES]
+experimental_library_files.append('src/macros.py')
+env.JS2C(['src/experimental-libraries.cc'],
+         experimental_library_files,
+         TYPE='EXPERIMENTAL',
+         COMPRESSION='off')
+library_files = [('src/'+s) for s in LIBRARY_FILES]
+library_files.append('src/macros.py')
+env.JS2C(['src/libraries.cc'], library_files, TYPE='CORE', COMPRESSION='off')
+
+env.StaticLibrary("v8", sources)
