summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoragirbal <antoine@10gen.com>2011-04-27 11:57:10 -0700
committeragirbal <antoine@10gen.com>2011-05-02 16:08:41 -0700
commit1725803c209ddf6ca52190447ddb1bdbc7371719 (patch)
tree4af2d44f3eeb3340ba0f5d5c902ce098b5389338
parent52c03d3954fe7bc988a04b05e28882a266f5be0d (diff)
downloadmongo-1725803c209ddf6ca52190447ddb1bdbc7371719.tar.gz
SERVER-2579: all v8 object creation is now lazy.
Correct allocation and freeing of underlying C++ object. Correct ordering of object properties even when new ones are added within JS. Supports deletion of properties with lazzy wrapper. Also removed scope->setThis in favor of passing it in the invoke() command.
-rw-r--r--db/commands/group.cpp7
-rw-r--r--db/commands/mr.cpp7
-rw-r--r--db/dbeval.cpp2
-rw-r--r--db/matcher.cpp4
-rw-r--r--dbtests/jstests.cpp12
-rw-r--r--scripting/engine.cpp14
-rw-r--r--scripting/engine.h14
-rw-r--r--scripting/engine_spidermonkey.cpp12
-rw-r--r--scripting/engine_v8.cpp187
-rw-r--r--scripting/engine_v8.h10
-rw-r--r--scripting/v8_db.cpp2
-rw-r--r--shell/dbshell.cpp3
12 files changed, 156 insertions, 118 deletions
diff --git a/db/commands/group.cpp b/db/commands/group.cpp
index 422c35588b7..be6213da889 100644
--- a/db/commands/group.cpp
+++ b/db/commands/group.cpp
@@ -36,7 +36,8 @@ namespace mongo {
if ( func ) {
BSONObjBuilder b( obj.objsize() + 32 );
b.append( "0" , obj );
- int res = s->invoke( func , b.obj() );
+ const BSONObj& key = b.obj();
+ int res = s->invoke( func , &key, 0 );
uassert( 10041 , (string)"invoke failed in $keyf: " + s->getError() , res == 0 );
int type = s->type("return");
uassert( 10042 , "return of $key has to be an object" , type == Object );
@@ -110,7 +111,7 @@ namespace mongo {
s->setObject( "obj" , obj , true );
s->setNumber( "n" , n - 1 );
- if ( s->invoke( f , BSONObj() , 0 , true ) ) {
+ if ( s->invoke( f , 0, 0 , 0 , true ) ) {
throw UserException( 9010 , (string)"reduce invoke failed: " + s->getError() );
}
}
@@ -125,7 +126,7 @@ namespace mongo {
" $arr[i] = ret; "
" } "
"}" );
- s->invoke( g , BSONObj() , 0 , true );
+ s->invoke( g , 0, 0 , 0 , true );
}
result.appendArray( "retval" , s->getObject( "$arr" ) );
diff --git a/db/commands/mr.cpp b/db/commands/mr.cpp
index 75d65553edc..f70922a6eef 100644
--- a/db/commands/mr.cpp
+++ b/db/commands/mr.cpp
@@ -66,8 +66,7 @@ namespace mongo {
void JSMapper::map( const BSONObj& o ) {
Scope * s = _func.scope();
assert( s );
- s->setThis( &o );
- if ( s->invoke( _func.func() , _params , 0 , true ) )
+ if ( s->invoke( _func.func() , &_params, &o , 0 , true ) )
throw UserException( 9014, str::stream() << "map invoke failed: " + s->getError() );
}
@@ -79,7 +78,7 @@ namespace mongo {
Scope * s = _func.scope();
Scope::NoDBAccess no = s->disableDBAccess( "can't access db inside finalize" );
- s->invokeSafe( _func.func() , o );
+ s->invokeSafe( _func.func() , &o, 0 );
// don't want to use o.objsize() to size b
// since there are many cases where the point of finalize
@@ -183,7 +182,7 @@ namespace mongo {
Scope * s = _func.scope();
- s->invokeSafe( _func.func() , args );
+ s->invokeSafe( _func.func() , &args, 0 );
if ( s->type( "return" ) == Array ) {
uasserted( 10075 , "reduce -> multiple not supported yet");
diff --git a/db/dbeval.cpp b/db/dbeval.cpp
index 31d52609b6e..5a0671296e6 100644
--- a/db/dbeval.cpp
+++ b/db/dbeval.cpp
@@ -86,7 +86,7 @@ namespace mongo {
int res;
{
Timer t;
- res = s->invoke(f,args, cmdLine.quota ? 10 * 60 * 1000 : 0 );
+ res = s->invoke(f, &args, 0, cmdLine.quota ? 10 * 60 * 1000 : 0 );
int m = t.millis();
if ( m > cmdLine.slowMS ) {
out() << "dbeval slow, time: " << dec << m << "ms " << dbName << endl;
diff --git a/db/matcher.cpp b/db/matcher.cpp
index 4a96f5c38ca..c210984d55d 100644
--- a/db/matcher.cpp
+++ b/db/matcher.cpp
@@ -892,12 +892,10 @@ namespace mongo {
if ( where->jsScope ) {
where->scope->init( where->jsScope );
}
- where->scope->setThis( const_cast< BSONObj * >( &jsobj ) );
where->scope->setObject( "obj", const_cast< BSONObj & >( jsobj ) );
where->scope->setBoolean( "fullObject" , true ); // this is a hack b/c fullObject used to be relevant
- int err = where->scope->invoke( where->func , BSONObj() , 1000 * 60 , false );
- where->scope->setThis( 0 );
+ int err = where->scope->invoke( where->func , 0, &jsobj , 1000 * 60 , false );
if ( err == -3 ) { // INVOKE_ERROR
stringstream ss;
ss << "error on invocation of $where function:\n"
diff --git a/dbtests/jstests.cpp b/dbtests/jstests.cpp
index c33b2005b38..3611a2ce998 100644
--- a/dbtests/jstests.cpp
+++ b/dbtests/jstests.cpp
@@ -143,8 +143,7 @@ namespace JSTests {
s->invoke( "return blah.y;" , BSONObj() );
ASSERT_EQUALS( "eliot" , s->getString( "return" ) );
- s->setThis( & o );
- s->invoke( "return this.z;" , BSONObj() );
+ s->invoke( "return this.z;" , 0, &o );
ASSERT_EQUALS( "sara" , s->getString( "return" ) );
s->invoke( "return this.z == 'sara';" , BSONObj() );
@@ -715,9 +714,8 @@ namespace JSTests {
}
//cout << "ELIOT: " << b.jsonString() << endl;
- s->setThis( &b );
// its ok if this is handled by js, just can't create a c++ exception
- s->invoke( "x=this.x.length;" , BSONObj() );
+ s->invoke( "x=this.x.length;" , 0, &b );
}
};
@@ -903,12 +901,11 @@ namespace JSTests {
s.reset( globalScriptEngine->newScope() );
ScriptingFunction f = s->createFunction( "return this.x + 6;" );
- s->setThis( &start );
Timer t;
double n = 0;
for ( ; n < 100000; n++ ) {
- s->invoke( f , empty );
+ s->invoke( f , &empty, &start );
ASSERT_EQUALS( 11 , s->getNumber( "return" ) );
}
//cout << "speed1: " << ( n / t.millis() ) << " ops/ms" << endl;
@@ -934,10 +931,9 @@ namespace JSTests {
BSONObjBuilder b;
s->append( b , "z" , "x" );
temp = b.obj();
- s->setThis( &temp );
}
- s->invokeSafe( "foo = this.z();" , BSONObj() );
+ s->invokeSafe( "foo = this.z();" , 0, &temp );
ASSERT_EQUALS( 17 , s->getNumber( "foo" ) );
}
};
diff --git a/scripting/engine.cpp b/scripting/engine.cpp
index f995f7a4079..3f6c84cc143 100644
--- a/scripting/engine.cpp
+++ b/scripting/engine.cpp
@@ -85,10 +85,10 @@ namespace mongo {
}
- int Scope::invoke( const char* code , const BSONObj& args, int timeoutMs ) {
+ int Scope::invoke( const char* code , const BSONObj* args, const BSONObj* recv, int timeoutMs ) {
ScriptingFunction func = createFunction( code );
uassert( 10207 , "compile failed" , func );
- return invoke( func , args, timeoutMs );
+ return invoke( func , args, recv, timeoutMs );
}
bool Scope::execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs ) {
@@ -394,9 +394,9 @@ namespace mongo {
void setBoolean( const char *field , bool val ) {
_real->setBoolean( field , val );
}
- void setThis( const BSONObj * obj ) {
- _real->setThis( obj );
- }
+// void setThis( const BSONObj * obj ) {
+// _real->setThis( obj );
+// }
ScriptingFunction createFunction( const char * code ) {
return _real->createFunction( code );
@@ -413,8 +413,8 @@ namespace mongo {
/**
* @return 0 on success
*/
- int invoke( ScriptingFunction func , const BSONObj& args, int timeoutMs , bool ignoreReturn ) {
- return _real->invoke( func , args , timeoutMs , ignoreReturn );
+ int invoke( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs , bool ignoreReturn ) {
+ return _real->invoke( func , args , recv, timeoutMs , ignoreReturn );
}
string getError() {
diff --git a/scripting/engine.h b/scripting/engine.h
index e2aeb423e00..bec8abc76df 100644
--- a/scripting/engine.h
+++ b/scripting/engine.h
@@ -76,7 +76,7 @@ namespace mongo {
virtual void setString( const char *field , const char * val ) = 0;
virtual void setObject( const char *field , const BSONObj& obj , bool readOnly=true ) = 0;
virtual void setBoolean( const char *field , bool val ) = 0;
- virtual void setThis( const BSONObj * obj ) = 0;
+// virtual void setThis( const BSONObj * obj ) = 0;
virtual ScriptingFunction createFunction( const char * code );
@@ -84,18 +84,18 @@ namespace mongo {
/**
* @return 0 on success
*/
- virtual int invoke( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 , bool ignoreReturn = false ) = 0;
- void invokeSafe( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 ) {
- int res = invoke( func , args , timeoutMs );
+ virtual int invoke( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false ) = 0;
+ void invokeSafe( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 ) {
+ int res = invoke( func , args , recv, timeoutMs );
if ( res == 0 )
return;
throw UserException( 9004 , (string)"invoke failed: " + getError() );
}
virtual string getError() = 0;
- int invoke( const char* code , const BSONObj& args, int timeoutMs = 0 );
- void invokeSafe( const char* code , const BSONObj& args, int timeoutMs = 0 ) {
- if ( invoke( code , args , timeoutMs ) == 0 )
+ int invoke( const char* code , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 );
+ void invokeSafe( const char* code , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 ) {
+ if ( invoke( code , args , recv, timeoutMs ) == 0 )
return;
throw UserException( 9005 , (string)"invoke failed: " + getError() );
}
diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp
index b455145568e..0dfee9a568a 100644
--- a/scripting/engine_spidermonkey.cpp
+++ b/scripting/engine_spidermonkey.cpp
@@ -1463,13 +1463,13 @@ namespace mongo {
return worked;
}
- int invoke( JSFunction * func , const BSONObj& args, int timeoutMs , bool ignoreReturn ) {
+ int invoke( JSFunction * func , const BSONObj* args, const BSONObj* recv, int timeoutMs , bool ignoreReturn ) {
smlock;
precall();
assert( JS_EnterLocalRootScope( _context ) );
- int nargs = args.nFields();
+ int nargs = args ? args->nFields() : 0;
scoped_array<jsval> smargsPtr( new jsval[nargs] );
if ( nargs ) {
BSONObjIterator it( args );
@@ -1478,18 +1478,20 @@ namespace mongo {
}
}
- if ( args.isEmpty() ) {
+ if ( !args ) {
_convertor->setProperty( _global , "args" , JSVAL_NULL );
}
else {
- setObject( "args" , args , true ); // this is for backwards compatability
+ setObject( "args" , *args , true ); // this is for backwards compatability
}
JS_LeaveLocalRootScope( _context );
installInterrupt( timeoutMs );
jsval rval;
+ setThis(recv);
JSBool ret = JS_CallFunction( _context , _this ? _this : _global , func , nargs , smargsPtr.get() , &rval );
+ setThis(0);
uninstallInterrupt( timeoutMs );
if ( !ret ) {
@@ -1503,7 +1505,7 @@ namespace mongo {
return 0;
}
- int invoke( ScriptingFunction funcAddr , const BSONObj& args, int timeoutMs = 0 , bool ignoreReturn = 0 ) {
+ int invoke( ScriptingFunction funcAddr , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = 0 ) {
return invoke( (JSFunction*)funcAddr , args , timeoutMs , ignoreReturn );
}
diff --git a/scripting/engine_v8.cpp b/scripting/engine_v8.cpp
index 7f3f5cee5e5..d3f40265e1d 100644
--- a/scripting/engine_v8.cpp
+++ b/scripting/engine_v8.cpp
@@ -39,9 +39,26 @@ namespace mongo {
return static_cast<BSONObj*>(ptr);
}
+ static void weakRefCallback(v8::Persistent<v8::Value> p, void* scope) {
+ // should we lock here? no idea, and no doc from v8 of course
+ HandleScope handle_scope;
+ if (!p.IsNearDeath())
+ return;
+ BSONObj* obj = unwrapBSONObj(v8::Persistent<v8::Object>::Cast(p));
+ delete obj;
+ p.Dispose();
+ cout << "deleted obj" << endl;
+ }
+
static Handle<v8::Value> namedGet(Local<v8::String> name, const v8::AccessorInfo &info) {
- if (info.This()->HasRealNamedProperty(name)) {
- return info.This()->GetRealNamedProperty(name);
+ // all properties should be set, otherwise means builtin or deleted
+ if (!(info.This()->HasRealNamedProperty(name)))
+ return v8::Handle<v8::Value>();
+
+ Handle<v8::Value> val = info.This()->GetRealNamedProperty(name);
+ if (!val->IsUndefined()) {
+ // value already cached
+ return val;
}
string key = toSTLString(name);
@@ -51,8 +68,8 @@ namespace mongo {
BSONElement elmt = obj->getField(key.c_str());
Local< External > scp = External::Cast( *info.Data() );
V8Scope* scope = (V8Scope*)(scp->Value());
- Handle<Value> val = scope->mongoToV8Element(elmt, true);
- info.This()->ForceSet(name, val, DontEnum);
+ val = scope->mongoToV8Element(elmt);
+ info.This()->ForceSet(name, val);
return val;
}
@@ -60,21 +77,21 @@ namespace mongo {
// return Handle<Value>();
// }
- static Handle<v8::Array> namedEnumerator(const AccessorInfo &info) {
- BSONObj *obj = unwrapBSONObj(info.Holder());
- Handle<v8::Array> arr = Handle<v8::Array>(v8::Array::New(obj->nFields()));
- int i = 0;
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- // note here that if keys are parseable number, v8 will access them using index
- for ( BSONObjIterator it(*obj); it.more(); ++i) {
- const BSONElement& f = it.next();
-// arr->Set(i, v8::String::NewExternal(new ExternalString(f.fieldName())));
- Handle<v8::String> name = scope->getV8Str(f.fieldName());
- arr->Set(i, name);
- }
- return arr;
- }
+// static Handle<v8::Array> namedEnumerator(const AccessorInfo &info) {
+// BSONObj *obj = unwrapBSONObj(info.Holder());
+// Handle<v8::Array> arr = Handle<v8::Array>(v8::Array::New(obj->nFields()));
+// int i = 0;
+// Local< External > scp = External::Cast( *info.Data() );
+// V8Scope* scope = (V8Scope*)(scp->Value());
+// // note here that if keys are parseable number, v8 will access them using index
+// for ( BSONObjIterator it(*obj); it.more(); ++i) {
+// const BSONElement& f = it.next();
+//// arr->Set(i, v8::String::NewExternal(new ExternalString(f.fieldName())));
+// Handle<v8::String> name = scope->getV8Str(f.fieldName());
+// arr->Set(i, name);
+// }
+// return arr;
+// }
// v8::Handle<v8::Integer> namedQuery(Local<v8::String> property, const AccessorInfo& info) {
// string key = ToString(property);
@@ -82,21 +99,29 @@ namespace mongo {
// }
static Handle<v8::Value> indexedGet(uint32_t index, const v8::AccessorInfo &info) {
+ // all properties should be set, otherwise means builtin or deleted
+ if (!(info.This()->HasRealIndexedProperty(index)))
+ return v8::Handle<v8::Value>();
+
StringBuilder ss;
ss << index;
string key = ss.str();
Local< External > scp = External::Cast( *info.Data() );
V8Scope* scope = (V8Scope*)(scp->Value());
- Handle<v8::String> name = scope->getV8Str(key);
- // v8 API really confusing here, must check existence on index, but then fetch with name
- if (info.This()->HasRealIndexedProperty(index))
- return info.This()->GetRealNamedProperty(name);
+ // cannot get v8 to properly cache the indexed val in the js object
+// Handle<v8::String> name = scope->getV8Str(key);
+// // v8 API really confusing here, must check existence on index, but then fetch with name
+// if (info.This()->HasRealIndexedProperty(index)) {
+// Handle<v8::Value> val = info.This()->GetRealNamedProperty(name);
+// if (!val.IsEmpty() && !val->IsNull())
+// return val;
+// }
BSONObj *obj = unwrapBSONObj(info.Holder());
if (!obj || !obj->hasElement(key.c_str()))
return Handle<Value>();
BSONElement elmt = obj->getField(key);
- Handle<Value> val = scope->mongoToV8Element(elmt, true);
- info.This()->ForceSet(name, val);
+ Handle<Value> val = scope->mongoToV8Element(elmt);
+// info.This()->ForceSet(name, val);
return val;
}
@@ -104,19 +129,19 @@ namespace mongo {
// return Handle<Value>();
// }
- static Handle<v8::Array> indexedEnumerator(const AccessorInfo &info) {
- BSONObj *obj = unwrapBSONObj(info.Holder());
- Handle<v8::Array> arr = Handle<v8::Array>(v8::Array::New(obj->nFields()));
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- int i = 0;
- for ( BSONObjIterator it(*obj); it.more(); ++i) {
- const BSONElement& f = it.next();
-// arr->Set(i, v8::String::NewExternal(new ExternalString(f.fieldName())));
- arr->Set(i, scope->getV8Str(f.fieldName()));
- }
- return arr;
- }
+// static Handle<v8::Array> indexedEnumerator(const AccessorInfo &info) {
+// BSONObj *obj = unwrapBSONObj(info.Holder());
+// Handle<v8::Array> arr = Handle<v8::Array>(v8::Array::New(obj->nFields()));
+// Local< External > scp = External::Cast( *info.Data() );
+// V8Scope* scope = (V8Scope*)(scp->Value());
+// int i = 0;
+// for ( BSONObjIterator it(*obj); it.more(); ++i) {
+// const BSONElement& f = it.next();
+//// arr->Set(i, v8::String::NewExternal(new ExternalString(f.fieldName())));
+// arr->Set(i, scope->getV8Str(f.fieldName()));
+// }
+// return arr;
+// }
// --- engine ---
@@ -160,12 +185,12 @@ namespace mongo {
_context = Context::New();
Context::Scope context_scope( _context );
_global = Persistent< v8::Object >::New( _context->Global() );
- _this = Persistent< v8::Object >::New( v8::Object::New() );
+ _emptyObj = Persistent< v8::Object >::New( v8::Object::New() );
// initialize lazy object template
lzObjectTemplate = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
lzObjectTemplate->SetInternalFieldCount( 1 );
- lzObjectTemplate->SetNamedPropertyHandler(namedGet, 0, 0, 0, namedEnumerator, v8::External::New(this));
+ lzObjectTemplate->SetNamedPropertyHandler(namedGet, 0, 0, 0, 0, v8::External::New(this));
lzObjectTemplate->SetIndexedPropertyHandler(indexedGet, 0, 0, 0, 0, v8::External::New(this));
// initialize lazy array template
@@ -174,7 +199,7 @@ namespace mongo {
// this it creates issues when calling certain methods that check array type
lzArrayTemplate = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
lzArrayTemplate->SetInternalFieldCount( 1 );
- lzArrayTemplate->SetIndexedPropertyHandler(indexedGet, 0, 0, 0, indexedEnumerator, v8::External::New(this));
+ lzArrayTemplate->SetIndexedPropertyHandler(indexedGet, 0, 0, 0, 0, v8::External::New(this));
V8STR_CONN = getV8Str( "_conn" );
V8STR_ID = getV8Str( "_id" );
@@ -208,7 +233,7 @@ namespace mongo {
V8Lock l;
Context::Scope context_scope( _context );
_wrapper.Dispose();
- _this.Dispose();
+ _emptyObj.Dispose();
for( unsigned i = 0; i < _funcs.size(); ++i )
_funcs[ i ].Dispose();
_funcs.clear();
@@ -480,18 +505,18 @@ namespace mongo {
return num;
}
- void V8Scope::setThis( const BSONObj * obj ) {
- V8_SIMPLE_HEADER
- if ( ! obj ) {
- _this = Persistent< v8::Object >::New( v8::Object::New() );
- return;
- }
-
- //_this = mongoToV8( *obj );
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::External::New( createWrapperHolder( this, obj , true , false ) );
- _this = Persistent< v8::Object >::New( _wrapper->NewInstance( 1, argv ) );
- }
+// void V8Scope::setThis( const BSONObj * obj ) {
+// V8_SIMPLE_HEADER
+// if ( ! obj ) {
+// _this = Persistent< v8::Object >::New( v8::Object::New() );
+// return;
+// }
+//
+// //_this = mongoToV8( *obj );
+// v8::Handle<v8::Value> argv[1];
+// argv[0] = v8::External::New( createWrapperHolder( this, obj , true , false ) );
+// _this = Persistent< v8::Object >::New( _wrapper->NewInstance( 1, argv ) );
+// }
void V8Scope::rename( const char * from , const char * to ) {
V8_SIMPLE_HEADER;
@@ -501,21 +526,21 @@ namespace mongo {
_global->Set( f , v8::Undefined() );
}
- int V8Scope::invoke( ScriptingFunction func , const BSONObj& argsObject, int timeoutMs , bool ignoreReturn ) {
+ int V8Scope::invoke( ScriptingFunction func , const BSONObj* argsObject, const BSONObj* recv, int timeoutMs , bool ignoreReturn ) {
V8_SIMPLE_HEADER
Handle<Value> funcValue = _funcs[func-1];
TryCatch try_catch;
- int nargs = argsObject.nFields();
+ int nargs = argsObject ? argsObject->nFields() : 0;
scoped_array< Handle<Value> > args;
if ( nargs ) {
args.reset( new Handle<Value>[nargs] );
- BSONObjIterator it( argsObject );
+ BSONObjIterator it( *argsObject );
for ( int i=0; i<nargs; i++ ) {
BSONElement next = it.next();
args[i] = mongoToV8Element( next );
}
- setObject( "args", argsObject, true ); // for backwards compatibility
+ setObject( "args", *argsObject, true ); // for backwards compatibility
}
else {
_global->Set( V8STR_ARGS, v8::Undefined() );
@@ -527,8 +552,14 @@ namespace mongo {
log() << _error << endl;
return 1;
}
+ Handle<v8::Object> v8recv;
+ if (recv != 0)
+ v8recv = mongoToLZV8(*recv, false);
+ else
+ v8recv = _emptyObj;
+
enableV8Interrupt(); // because of v8 locker we can check interrupted, then enable
- Local<Value> result = ((v8::Function*)(*funcValue))->Call( _this , nargs , args.get() );
+ Local<Value> result = ((v8::Function*)(*funcValue))->Call( v8recv , nargs , nargs ? args.get() : 0 );
disableV8Interrupt();
if ( result.IsEmpty() ) {
@@ -837,9 +868,12 @@ namespace mongo {
break;
case mongo::Array:
+ sub = f.embeddedObject();
+ o->Set( name , mongoToV8( sub , true, readOnly ) );
+ break;
case mongo::Object:
sub = f.embeddedObject();
- o->Set( name , mongoToV8( sub , f.type() == mongo::Array, readOnly ) );
+ o->Set( name , mongoToLZV8( sub , false, readOnly ) );
break;
case mongo::Date:
@@ -958,7 +992,7 @@ namespace mongo {
/**
* converts a BSONObj to a Lazy V8 object
*/
- Local<v8::Object> V8Scope::mongoToLZV8( const BSONObj& m , bool array, bool readOnly ) {
+ Handle<v8::Object> V8Scope::mongoToLZV8( const BSONObj& m , bool array, bool readOnly ) {
Local<v8::Object> o;
if (array) {
@@ -979,12 +1013,21 @@ namespace mongo {
}
}
- BSONObj* p = new BSONObj(m);
- o->SetInternalField(0, v8::External::New(p));
- return o;
+ o->SetInternalField(0, v8::External::New((new BSONObj( m.getOwned() ))));
+ // need to set all keys with dummy values, so that order of keys is correct during enumeration
+ // otherwise v8 will list any newly set property in JS before the ones of underlying BSON obj.
+ for (BSONObjIterator it(m); it.more();) {
+ const BSONElement& f = it.next();
+ o->ForceSet(getV8Str(f.fieldName()), v8::Undefined());
+ }
+
+ Persistent<v8::Object> p = Persistent<v8::Object>::New(o);
+ p.MakeWeak(this, weakRefCallback);
+ cout << "created obj" << endl;
+ return p;
}
- Handle<v8::Value> V8Scope::mongoToV8Element( const BSONElement &f, bool lazy ) {
+ Handle<v8::Value> V8Scope::mongoToV8Element( const BSONElement &f ) {
Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New();
internalFieldObjects->SetInternalFieldCount( 1 );
@@ -1013,11 +1056,9 @@ namespace mongo {
// - the lazy array is not a true v8 array and requires some v8 src change for all methods to work
// - it made several tests about 1.5x slower
// - most times when an array is accessed, all its values will be used
- return mongoToV8( f.embeddedObject() , f.type() == mongo::Array );
+ return mongoToV8( f.embeddedObject() , true );
case mongo::Object:
- if (lazy)
- return mongoToLZV8( f.embeddedObject() , f.type() == mongo::Array);
- return mongoToV8( f.embeddedObject() , f.type() == mongo::Array );
+ return mongoToLZV8( f.embeddedObject() , false);
case mongo::Date:
return v8::Date::New( f.date() );
@@ -1252,11 +1293,11 @@ namespace mongo {
Local<v8::Array> names = o->GetPropertyNames();
for ( unsigned int i=0; i<names->Length(); i++ ) {
- v8::Local<v8::String> name = names->Get(v8::Integer::New(i) )->ToString();
+ v8::Local<v8::String> name = names->Get( i )->ToString();
- if ( o->GetPrototype()->IsObject() &&
- o->GetPrototype()->ToObject()->HasRealNamedProperty( name ) )
- continue;
+// if ( o->GetPrototype()->IsObject() &&
+// o->GetPrototype()->ToObject()->HasRealNamedProperty( name ) )
+// continue;
v8::Local<v8::Value> value = o->Get( name );
diff --git a/scripting/engine_v8.h b/scripting/engine_v8.h
index bc4fec222b8..f8acc9d1346 100644
--- a/scripting/engine_v8.h
+++ b/scripting/engine_v8.h
@@ -85,13 +85,13 @@ namespace mongo {
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 setThis( const BSONObj * obj );
+// virtual void setThis( const BSONObj * obj );
virtual void rename( const char * from , const char * to );
virtual ScriptingFunction _createFunction( const char * code );
Local< v8::Function > __createFunction( const char * code );
- virtual int invoke( ScriptingFunction func , const BSONObj& args, int timeoutMs = 0 , bool ignoreReturn = false );
+ virtual int invoke( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false );
virtual bool exec( const StringData& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs );
virtual string getError() { return _error; }
@@ -107,12 +107,12 @@ namespace mongo {
Handle< Context > context() const { return _context; }
v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false );
- v8::Local<v8::Object> mongoToLZV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false );
+ v8::Handle<v8::Object> mongoToLZV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false );
mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth = 0 );
void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name ,
const string sname , v8::Handle<v8::Value> value , int depth = 0 );
- v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool lazy = true );
+ v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f );
v8::Function * getNamedCons( const char * name );
v8::Function * getObjectIdCons();
@@ -156,7 +156,7 @@ namespace mongo {
string _error;
vector< Persistent<Value> > _funcs;
- v8::Persistent<v8::Object> _this;
+ v8::Persistent<v8::Object> _emptyObj;
v8::Persistent<v8::Function> _wrapper;
diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp
index 6c4fdec505d..bb80957c8e6 100644
--- a/scripting/v8_db.cpp
+++ b/scripting/v8_db.cpp
@@ -403,7 +403,7 @@ namespace mongo {
V8Unlock u;
o = cursor->next();
}
- return scope->mongoToV8( o );
+ return scope->mongoToLZV8( o );
}
v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args) {
diff --git a/shell/dbshell.cpp b/shell/dbshell.cpp
index 9868c427ecb..5a3cf375b4d 100644
--- a/shell/dbshell.cpp
+++ b/shell/dbshell.cpp
@@ -66,7 +66,8 @@ void generateCompletions( const string& prefix , vector<string>& all ) {
if ( prefix.find( '"' ) != string::npos )
return;
- shellMainScope->invokeSafe("function(x) {shellAutocomplete(x)}", BSON("0" << prefix), 1000);
+ BSONObj args = BSON("0" << prefix);
+ shellMainScope->invokeSafe("function(x) {shellAutocomplete(x)}", &args, 0, 1000);
BSONObjBuilder b;
shellMainScope->append( b , "" , "__autocomplete__" );
BSONObj res = b.obj();