void operator()() { Locker l; HandleScope handle_scope; Handle< Context > context; Handle< v8::Function > fun; auto_ptr< V8Scope > scope; if ( config_.newScope_ ) { scope.reset( dynamic_cast< V8Scope * >( globalScriptEngine->newScope() ) ); context = scope->context(); // A v8::Function tracks the context in which it was created, so we have to // create a new function in the new context. Context::Scope baseScope( baseContext_ ); string fCode = toSTLString( config_.f_->ToString() ); Context::Scope context_scope( context ); fun = scope->__createFunction( fCode.c_str() ); } else { context = baseContext_; Context::Scope context_scope( context ); fun = config_.f_; } Context::Scope context_scope( context ); boost::scoped_array< Local< Value > > argv( new Local< Value >[ config_.args_.size() ] ); for( unsigned int i = 0; i < config_.args_.size(); ++i ) argv[ i ] = Local< Value >::New( config_.args_[ i ] ); TryCatch try_catch; Handle< Value > ret = fun->Call( context->Global(), config_.args_.size(), argv.get() ); if ( ret.IsEmpty() ) { string e = toSTLString( &try_catch ); log() << "js thread raised exception: " << e << endl; // v8 probably does something sane if ret is empty, but not going to assume that for now ret = v8::Undefined(); } config_.returnData_ = Persistent< Value >::New( ret ); }
void operator()() { V8Scope* scope = config_._scope.get(); v8::Isolate::Scope iscope(scope->getIsolate()); v8::Locker l(scope->getIsolate()); HandleScope handle_scope; Context::Scope context_scope( scope->getContext() ); BSONObj args = config_.args_; Local< v8::Function > f = v8::Function::Cast( *(scope->mongoToV8Element(args.firstElement(), true)) ); int argc = args.nFields() - 1; boost::scoped_array< Local< Value > > argv( new Local< Value >[ argc ] ); BSONObjIterator it(args); it.next(); for( int i = 0; i < argc; ++i ) { argv[ i ] = Local< Value >::New( scope->mongoToV8Element(*it, true) ); it.next(); } TryCatch try_catch; Handle< Value > ret = f->Call( scope->getContext()->Global(), argc, argv.get() ); if ( ret.IsEmpty() ) { string e = toSTLString( &try_catch ); log() << "js thread raised exception: " << e << endl; // v8 probably does something sane if ret is empty, but not going to assume that for now ret = v8::Undefined(); } // ret is translated to BSON to switch isolate BSONObjBuilder b; scope->v8ToMongoElement(b, "ret", ret); config_.returnData_ = b.obj(); }
int V8Scope::invoke( ScriptingFunction func , const BSONObj& argsObject, int timeoutMs , bool ignoreReturn ){ Handle<Value> funcValue = _funcs[func-1]; TryCatch try_catch; int nargs = argsObject.nFields(); auto_ptr< Handle<Value> > args; if ( nargs ){ args.reset( new Handle<Value>[nargs] ); BSONObjIterator it( argsObject ); for ( int i=0; i<nargs; i++ ){ BSONElement next = it.next(); args.get()[i] = mongoToV8Element( next ); } } Local<Value> result = ((v8::Function*)(*funcValue))->Call( _this , nargs , args.get() ); if ( result.IsEmpty() ){ stringstream ss; ss << "error in invoke: " << toSTLString( &try_catch ); _error = ss.str(); log() << _error << endl; return 1; } if ( ! ignoreReturn ){ _global->Set( v8::String::New( "return" ) , result ); } return 0; }
void operator()() { config_._scope.reset( dynamic_cast< V8Scope * >( globalScriptEngine->newScope() ) ); v8::Locker v8lock(config_._scope->getIsolate()); v8::Isolate::Scope iscope(config_._scope->getIsolate()); HandleScope handle_scope; Context::Scope context_scope(config_._scope->getContext()); BSONObj args = config_.args_; 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 Local<Value> argv[24]; BSONObjIterator it(args); it.next(); for(int i = 0; i < argc && i < 24; ++i) { argv[i] = Local< Value >::New(config_._scope->mongoToV8Element(*it, true)); it.next(); } TryCatch try_catch; Handle<Value> ret = f->Call(config_._scope->getContext()->Global(), argc, argv); if (ret.IsEmpty() || try_catch.HasCaught()) { string e = toSTLString( &try_catch ); log() << "js thread raised exception: " << e << endl; // v8 probably does something sane if ret is empty, but not going to assume that for now ret = v8::Undefined(); } // ret is translated to BSON to switch isolate BSONObjBuilder b; config_._scope->v8ToMongoElement(b, "ret", ret); config_.returnData_ = b.obj(); }
BSONObj v8ToMongo( v8::Handle<v8::Object> o ){ BSONObjBuilder b; v8::Handle<v8::String> idName = v8::String::New( "_id" ); if ( o->HasRealNamedProperty( idName ) ){ v8ToMongoElement( b , idName , "_id" , o->Get( idName ) ); } 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(); if ( o->GetPrototype()->IsObject() && o->GetPrototype()->ToObject()->HasRealNamedProperty( name ) ) continue; v8::Local<v8::Value> value = o->Get( name ); const string sname = toSTLString( name ); if ( sname == "_id" ) continue; v8ToMongoElement( b , name , sname , value ); } return b.obj(); }
bool V8Scope::exec( const string& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs ){ if ( timeoutMs ){ static bool t = 1; if ( t ){ log() << "timeoutMs not support for v8 yet" << endl; t = 0; } } HandleScope handle_scope; TryCatch try_catch; Handle<Script> script = v8::Script::Compile( v8::String::New( code.c_str() ) , v8::String::New( name.c_str() ) ); if (script.IsEmpty()) { stringstream ss; ss << "compile error: " << toSTLString( &try_catch ); _error = ss.str(); if (reportError) log() << _error << endl; if ( assertOnError ) uassert( _error , 0 ); return false; } Handle<v8::Value> result = script->Run(); if ( result.IsEmpty() ){ _error = (string)"exec error: " + toSTLString( &try_catch ); if ( reportError ) log() << _error << endl; if ( assertOnError ) uassert( _error , 0 ); return false; } _global->Set( v8::String::New( "__lastres__" ) , result ); if ( printResult && ! result->IsUndefined() ){ cout << toSTLString( result ) << endl; } return true; }
ScriptingFunction V8Scope::_createFunction( const char * raw ){ string code = raw; if ( code.find( "function" ) == string::npos ){ if ( code.find( "\n" ) == string::npos && code.find( "return" ) == string::npos && ( code.find( ";" ) == string::npos || code.find( ";" ) == code.size() - 1 ) ){ code = "return " + code; } code = "function(){ " + code + "}"; } int num = _funcs.size() + 1; string fn; { stringstream ss; ss << "_funcs" << num; fn = ss.str(); } code = fn + " = " + code; TryCatch try_catch; Handle<Script> script = v8::Script::Compile( v8::String::New( code.c_str() ) , v8::String::New( fn.c_str() ) ); if ( script.IsEmpty() ){ _error = (string)"compile error: " + toSTLString( &try_catch ); log() << _error << endl; return 0; } Local<Value> result = script->Run(); if ( result.IsEmpty() ){ _error = (string)"compile error: " + toSTLString( &try_catch ); log() << _error << endl; return 0; } Handle<Value> f = _global->Get( v8::String::New( fn.c_str() ) ); uassert( "not a func" , f->IsFunction() ); _funcs.push_back( f ); return num; }
Handle< Value > V8Scope::loadCallback( const Arguments &args ) { HandleScope scope; Handle<External> field = Handle<External>::Cast(args.Data()); void* ptr = field->Value(); V8Scope* self = static_cast<V8Scope*>(ptr); Context::Scope context_scope(self->_context); for (int i = 0; i < args.Length(); ++i) { std::string filename(toSTLString(args[i])); if (!self->execFile(filename, false , true , false)) { return v8::ThrowException(v8::String::New((std::string("error loading file: ") + filename).c_str())); } } return v8::True(); }
virtual void serialize(std::stringstream& ss, size_t sz) const { ss << toSTLString(); }
string V8Scope::getString( const char *field ){ return toSTLString( get( field ) ); }
v8::Handle<v8::Value> get( v8::Local<v8::String> name ) { const string& s = toSTLString( name ); const BSONElement& e = _o->getField( s ); return _scope->mongoToV8Element(e); }
void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , const string sname , v8::Handle<v8::Value> value ){ if ( value->IsString() ){ if ( sname == "$where" ) b.appendCode( sname.c_str() , toSTLString( value ).c_str() ); else b.append( sname.c_str() , toSTLString( value ).c_str() ); return; } if ( value->IsFunction() ){ b.appendCode( sname.c_str() , toSTLString( value ).c_str() ); return; } if ( value->IsNumber() ){ b.append( sname.c_str() , value->ToNumber()->Value() ); return; } if ( value->IsArray() ){ BSONObj sub = v8ToMongo( value->ToObject() ); b.appendArray( sname.c_str() , sub ); return; } if ( value->IsDate() ){ b.appendDate( sname.c_str() , Date_t(v8::Date::Cast( *value )->NumberValue()) ); return; } if ( value->IsObject() ){ string s = toSTLString( value ); if ( s.size() && s[0] == '/' ){ s = s.substr( 1 ); string r = s.substr( 0 , s.find( "/" ) ); string o = s.substr( s.find( "/" ) + 1 ); b.appendRegex( sname.c_str() , r.c_str() , o.c_str() ); } else if ( value->ToObject()->GetPrototype()->IsObject() && value->ToObject()->GetPrototype()->ToObject()->HasRealNamedProperty( v8::String::New( "isObjectId" ) ) ){ OID oid; oid.init( toSTLString( value ) ); b.appendOID( sname.c_str() , &oid ); } else { BSONObj sub = v8ToMongo( value->ToObject() ); b.append( sname.c_str() , sub ); } return; } if ( value->IsBoolean() ){ b.appendBool( sname.c_str() , value->ToBoolean()->Value() ); return; } else if ( value->IsUndefined() ){ return; } else if ( value->IsNull() ){ b.appendNull( sname.c_str() ); return; } cout << "don't know how to convert to mongo field [" << name << "]\t" << value << endl; }