2011-01-04 06:40:41 +01:00
|
|
|
//engine_v8.cpp
|
2009-10-27 20:58:27 +01:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2009-05-04 17:49:18 +02:00
|
|
|
#include "engine_v8.h"
|
|
|
|
|
2009-10-10 07:30:00 +02:00
|
|
|
#include "v8_wrapper.h"
|
|
|
|
#include "v8_utils.h"
|
2009-10-13 16:48:38 +02:00
|
|
|
#include "v8_db.h"
|
2009-05-04 23:37:02 +02:00
|
|
|
|
2010-09-23 23:36:04 +02:00
|
|
|
#define V8_SIMPLE_HEADER V8Lock l; HandleScope handle_scope; Context::Scope context_scope( _context );
|
2009-12-29 20:13:08 +01:00
|
|
|
|
2009-05-04 17:49:18 +02:00
|
|
|
namespace mongo {
|
|
|
|
|
2010-09-23 23:36:04 +02:00
|
|
|
// guarded by v8 mutex
|
|
|
|
map< unsigned, int > __interruptSpecToThreadId;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-11 04:24:08 +02:00
|
|
|
// --- engine ---
|
|
|
|
|
2009-12-29 20:04:00 +01:00
|
|
|
V8ScriptEngine::V8ScriptEngine() {}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
V8ScriptEngine::~V8ScriptEngine() {
|
2009-10-10 07:30:00 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void ScriptEngine::setup() {
|
|
|
|
if ( !globalScriptEngine ) {
|
2009-05-04 23:37:02 +02:00
|
|
|
globalScriptEngine = new V8ScriptEngine();
|
|
|
|
}
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-09-23 23:36:04 +02:00
|
|
|
void V8ScriptEngine::interrupt( unsigned opSpec ) {
|
|
|
|
v8::Locker l;
|
|
|
|
if ( __interruptSpecToThreadId.count( opSpec ) ) {
|
|
|
|
V8::TerminateExecution( __interruptSpecToThreadId[ opSpec ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void V8ScriptEngine::interruptAll() {
|
|
|
|
v8::Locker l;
|
|
|
|
vector< int > toKill; // v8 mutex could potentially be yielded during the termination call
|
|
|
|
for( map< unsigned, int >::const_iterator i = __interruptSpecToThreadId.begin(); i != __interruptSpecToThreadId.end(); ++i ) {
|
|
|
|
toKill.push_back( i->second );
|
|
|
|
}
|
|
|
|
for( vector< int >::const_iterator i = toKill.begin(); i != toKill.end(); ++i ) {
|
2011-01-04 06:40:41 +01:00
|
|
|
V8::TerminateExecution( *i );
|
2010-09-23 23:36:04 +02:00
|
|
|
}
|
|
|
|
}
|
2009-10-10 07:30:00 +02:00
|
|
|
|
2009-10-11 04:24:08 +02:00
|
|
|
// --- scope ---
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
V8Scope::V8Scope( V8ScriptEngine * engine )
|
|
|
|
: _engine( engine ) ,
|
|
|
|
_connectState( NOT ) {
|
2009-12-29 20:04:00 +01:00
|
|
|
|
2010-09-23 23:36:04 +02:00
|
|
|
V8Lock l;
|
2011-01-04 06:40:41 +01:00
|
|
|
HandleScope handleScope;
|
2009-12-29 20:04:00 +01:00
|
|
|
_context = Context::New();
|
|
|
|
Context::Scope context_scope( _context );
|
|
|
|
_global = Persistent< v8::Object >::New( _context->Global() );
|
|
|
|
|
|
|
|
_this = Persistent< v8::Object >::New( v8::Object::New() );
|
2009-10-13 22:12:43 +02:00
|
|
|
|
2010-09-08 06:32:14 +02:00
|
|
|
_global->Set(v8::String::New("print"), newV8Function< Print >()->GetFunction() );
|
|
|
|
_global->Set(v8::String::New("version"), newV8Function< Version >()->GetFunction() );
|
2009-10-13 22:12:43 +02:00
|
|
|
|
2009-12-29 20:04:00 +01:00
|
|
|
_global->Set(v8::String::New("load"),
|
2010-09-08 06:32:14 +02:00
|
|
|
v8::FunctionTemplate::New( v8Callback< loadCallback >, v8::External::New(this))->GetFunction() );
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-07-05 06:54:17 +02:00
|
|
|
_wrapper = Persistent< v8::Function >::New( getObjectWrapperTemplate()->GetFunction() );
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-09-08 06:32:14 +02:00
|
|
|
_global->Set(v8::String::New("gc"), newV8Function< GCV8 >()->GetFunction() );
|
2010-07-05 06:54:17 +02:00
|
|
|
|
|
|
|
|
2009-10-13 22:12:43 +02:00
|
|
|
installDBTypes( _global );
|
2009-10-10 07:30:00 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
V8Scope::~V8Scope() {
|
2010-09-23 23:36:04 +02:00
|
|
|
V8Lock l;
|
2011-01-04 06:40:41 +01:00
|
|
|
Context::Scope context_scope( _context );
|
2009-12-29 20:04:00 +01:00
|
|
|
_wrapper.Dispose();
|
|
|
|
_this.Dispose();
|
|
|
|
for( unsigned i = 0; i < _funcs.size(); ++i )
|
|
|
|
_funcs[ i ].Dispose();
|
|
|
|
_funcs.clear();
|
|
|
|
_global.Dispose();
|
|
|
|
_context.Dispose();
|
2009-10-10 07:30:00 +02:00
|
|
|
}
|
|
|
|
|
2009-05-04 23:37:02 +02:00
|
|
|
Handle< Value > V8Scope::nativeCallback( const Arguments &args ) {
|
2010-09-23 23:36:04 +02:00
|
|
|
V8Lock l;
|
2009-12-29 20:04:00 +01:00
|
|
|
HandleScope handle_scope;
|
2009-05-04 23:37:02 +02:00
|
|
|
Local< External > f = External::Cast( *args.Callee()->Get( v8::String::New( "_native_function" ) ) );
|
2009-10-15 17:27:02 +02:00
|
|
|
NativeFunction function = (NativeFunction)(f->Value());
|
2009-05-04 23:37:02 +02:00
|
|
|
BSONObjBuilder b;
|
|
|
|
for( int i = 0; i < args.Length(); ++i ) {
|
|
|
|
stringstream ss;
|
|
|
|
ss << i;
|
|
|
|
v8ToMongoElement( b, v8::String::New( "foo" ), ss.str(), args[ i ] );
|
|
|
|
}
|
2009-10-15 17:27:02 +02:00
|
|
|
BSONObj nativeArgs = b.obj();
|
2009-05-04 23:37:02 +02:00
|
|
|
BSONObj ret;
|
|
|
|
try {
|
2009-10-15 17:27:02 +02:00
|
|
|
ret = function( nativeArgs );
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
catch( const std::exception &e ) {
|
2009-05-04 23:37:02 +02:00
|
|
|
return v8::ThrowException(v8::String::New(e.what()));
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
catch( ... ) {
|
|
|
|
return v8::ThrowException(v8::String::New("unknown exception"));
|
2009-05-04 23:37:02 +02:00
|
|
|
}
|
2009-12-29 20:04:00 +01:00
|
|
|
return handle_scope.Close( mongoToV8Element( ret.firstElement() ) );
|
2009-05-04 17:49:18 +02:00
|
|
|
}
|
|
|
|
|
2009-11-23 01:33:43 +01:00
|
|
|
Handle< Value > V8Scope::loadCallback( const Arguments &args ) {
|
2010-09-23 23:36:04 +02:00
|
|
|
V8Lock l;
|
2009-12-29 20:04:00 +01:00
|
|
|
HandleScope handle_scope;
|
2009-11-23 01:33:43 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2009-10-13 16:12:44 +02:00
|
|
|
// ---- global stuff ----
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::init( const BSONObj * data ) {
|
2010-09-23 23:36:04 +02:00
|
|
|
V8Lock l;
|
2009-10-13 16:12:44 +02:00
|
|
|
if ( ! data )
|
|
|
|
return;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-13 16:12:44 +02:00
|
|
|
BSONObjIterator i( *data );
|
2011-01-04 06:40:41 +01:00
|
|
|
while ( i.more() ) {
|
2009-10-13 16:12:44 +02:00
|
|
|
BSONElement e = i.next();
|
|
|
|
setElement( e.fieldName() , e );
|
|
|
|
}
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
void V8Scope::setNumber( const char * field , double val ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-10 07:30:00 +02:00
|
|
|
_global->Set( v8::String::New( field ) , v8::Number::New( val ) );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::setString( const char * field , const char * val ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-10 07:30:00 +02:00
|
|
|
_global->Set( v8::String::New( field ) , v8::String::New( val ) );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::setBoolean( const char * field , bool val ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-10 07:30:00 +02:00
|
|
|
_global->Set( v8::String::New( field ) , v8::Boolean::New( val ) );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::setElement( const char *field , const BSONElement& e ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-12 17:22:30 +02:00
|
|
|
_global->Set( v8::String::New( field ) , mongoToV8Element( e ) );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::setObject( const char *field , const BSONObj& obj , bool readOnly) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-12-16 00:52:41 +01:00
|
|
|
// Set() accepts a ReadOnly parameter, but this just prevents the field itself
|
|
|
|
// from being overwritten and doesn't protect the object stored in 'field'.
|
|
|
|
_global->Set( v8::String::New( field ) , mongoToV8( obj, false, readOnly) );
|
2009-10-12 17:22:30 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
int V8Scope::type( const char *field ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-13 16:12:44 +02:00
|
|
|
Handle<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;
|
|
|
|
if ( v->IsInt32() )
|
|
|
|
return NumberInt;
|
|
|
|
if ( v->IsNumber() )
|
|
|
|
return NumberDouble;
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( v->IsExternal() ) {
|
2009-12-28 22:43:43 +01:00
|
|
|
uassert( 10230 , "can't handle external yet" , 0 );
|
2009-10-13 16:12:44 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ( v->IsDate() )
|
|
|
|
return Date;
|
2009-12-17 02:33:30 +01:00
|
|
|
if ( v->IsObject() )
|
|
|
|
return Object;
|
2009-10-13 16:12:44 +02:00
|
|
|
|
2009-12-29 20:32:09 +01:00
|
|
|
throw UserException( 12509, (string)"don't know what this is: " + field );
|
2009-10-12 17:22:30 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
v8::Handle<v8::Value> V8Scope::get( const char * field ) {
|
2009-10-12 17:30:43 +02:00
|
|
|
return _global->Get( v8::String::New( field ) );
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
double V8Scope::getNumber( const char *field ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-12 17:30:43 +02:00
|
|
|
return get( field )->ToNumber()->Value();
|
2009-10-10 07:30:00 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
int V8Scope::getNumberInt( const char *field ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-27 21:23:07 +01:00
|
|
|
return get( field )->ToInt32()->Value();
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
long long V8Scope::getNumberLongLong( const char *field ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-27 21:23:07 +01:00
|
|
|
return get( field )->ToInteger()->Value();
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
string V8Scope::getString( const char *field ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-12 17:30:43 +02:00
|
|
|
return toSTLString( get( field ) );
|
2009-10-10 07:30:00 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
bool V8Scope::getBoolean( const char *field ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-12 17:30:43 +02:00
|
|
|
return get( field )->ToBoolean()->Value();
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
BSONObj V8Scope::getObject( const char * field ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-12 17:30:43 +02:00
|
|
|
Handle<Value> v = get( field );
|
|
|
|
if ( v->IsNull() || v->IsUndefined() )
|
|
|
|
return BSONObj();
|
2009-12-28 22:43:43 +01:00
|
|
|
uassert( 10231 , "not an object" , v->IsObject() );
|
2009-10-12 17:30:43 +02:00
|
|
|
return v8ToMongo( v->ToObject() );
|
2009-10-10 07:30:00 +02:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-13 16:12:44 +02:00
|
|
|
// --- functions -----
|
2009-10-11 04:24:08 +02:00
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
bool hasFunctionIdentifier( const string& code ) {
|
2010-10-04 23:44:11 +02:00
|
|
|
if ( code.size() < 9 || code.find( "function" ) != 0 )
|
|
|
|
return false;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-10-04 23:44:11 +02:00
|
|
|
return code[8] == ' ' || code[8] == '(';
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
Local< v8::Function > V8Scope::__createFunction( const char * raw ) {
|
2010-11-29 07:50:57 +01:00
|
|
|
raw = jsSkipWhiteSpace( raw );
|
2009-10-12 00:15:12 +02:00
|
|
|
string code = raw;
|
2010-10-04 23:44:11 +02:00
|
|
|
if ( !hasFunctionIdentifier( code ) ) {
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( code.find( "\n" ) == string::npos &&
|
|
|
|
! hasJSReturn( code ) &&
|
|
|
|
( code.find( ";" ) == string::npos || code.find( ";" ) == code.size() - 1 ) ) {
|
2009-10-12 17:25:49 +02:00
|
|
|
code = "return " + code;
|
|
|
|
}
|
2009-10-12 00:15:12 +02:00
|
|
|
code = "function(){ " + code + "}";
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-12 00:15:12 +02:00
|
|
|
int num = _funcs.size() + 1;
|
|
|
|
|
|
|
|
string fn;
|
|
|
|
{
|
|
|
|
stringstream ss;
|
|
|
|
ss << "_funcs" << num;
|
|
|
|
fn = ss.str();
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-12 00:15:12 +02:00
|
|
|
code = fn + " = " + code;
|
|
|
|
|
|
|
|
TryCatch try_catch;
|
2010-09-23 23:36:04 +02:00
|
|
|
// this might be time consuming, consider allowing an interrupt
|
2011-01-04 06:40:41 +01:00
|
|
|
Handle<Script> script = v8::Script::Compile( v8::String::New( code.c_str() ) ,
|
|
|
|
v8::String::New( fn.c_str() ) );
|
|
|
|
if ( script.IsEmpty() ) {
|
2009-10-12 00:15:12 +02:00
|
|
|
_error = (string)"compile error: " + toSTLString( &try_catch );
|
|
|
|
log() << _error << endl;
|
2009-12-30 02:29:24 +01:00
|
|
|
return Local< v8::Function >();
|
2009-10-12 00:15:12 +02:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-12 00:15:12 +02:00
|
|
|
Local<Value> result = script->Run();
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( result.IsEmpty() ) {
|
2009-10-12 00:15:12 +02:00
|
|
|
_error = (string)"compile error: " + toSTLString( &try_catch );
|
|
|
|
log() << _error << endl;
|
2009-12-30 02:29:24 +01:00
|
|
|
return Local< v8::Function >();
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
|
2009-12-30 02:29:24 +01:00
|
|
|
return v8::Function::Cast( *_global->Get( v8::String::New( fn.c_str() ) ) );
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
ScriptingFunction V8Scope::_createFunction( const char * raw ) {
|
2009-12-30 02:29:24 +01:00
|
|
|
V8_SIMPLE_HEADER
|
|
|
|
Local< Value > ret = __createFunction( raw );
|
|
|
|
if ( ret.IsEmpty() )
|
|
|
|
return 0;
|
|
|
|
Persistent<Value> f = Persistent< Value >::New( ret );
|
2009-12-29 20:32:09 +01:00
|
|
|
uassert( 10232, "not a func" , f->IsFunction() );
|
2009-12-30 02:29:24 +01:00
|
|
|
int num = _funcs.size() + 1;
|
2009-10-12 00:15:12 +02:00
|
|
|
_funcs.push_back( f );
|
|
|
|
return num;
|
|
|
|
}
|
2009-10-13 16:12:44 +02:00
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::setThis( const BSONObj * obj ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( ! obj ) {
|
2009-12-29 20:04:00 +01:00
|
|
|
_this = Persistent< v8::Object >::New( v8::Object::New() );
|
2009-10-21 17:40:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//_this = mongoToV8( *obj );
|
|
|
|
v8::Handle<v8::Value> argv[1];
|
|
|
|
argv[0] = v8::External::New( createWrapperHolder( obj , true , false ) );
|
2009-12-29 20:04:00 +01:00
|
|
|
_this = Persistent< v8::Object >::New( _wrapper->NewInstance( 1, argv ) );
|
2009-10-13 16:12:44 +02:00
|
|
|
}
|
2010-09-01 07:32:04 +02:00
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::rename( const char * from , const char * to ) {
|
2010-09-01 07:32:04 +02:00
|
|
|
V8_SIMPLE_HEADER;
|
|
|
|
v8::Local<v8::String> f = v8::String::New( from );
|
|
|
|
v8::Local<v8::String> t = v8::String::New( to );
|
|
|
|
_global->Set( t , _global->Get( f ) );
|
|
|
|
_global->Set( f , v8::Undefined() );
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
int V8Scope::invoke( ScriptingFunction func , const BSONObj& argsObject, int timeoutMs , bool ignoreReturn ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-12 00:15:12 +02:00
|
|
|
Handle<Value> funcValue = _funcs[func-1];
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
TryCatch try_catch;
|
2009-10-12 00:15:12 +02:00
|
|
|
int nargs = argsObject.nFields();
|
2009-12-22 00:36:00 +01:00
|
|
|
scoped_array< Handle<Value> > args;
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( nargs ) {
|
2009-10-12 00:15:12 +02:00
|
|
|
args.reset( new Handle<Value>[nargs] );
|
|
|
|
BSONObjIterator it( argsObject );
|
2011-01-04 06:40:41 +01:00
|
|
|
for ( int i=0; i<nargs; i++ ) {
|
2009-10-12 00:15:12 +02:00
|
|
|
BSONElement next = it.next();
|
2009-12-22 00:36:00 +01:00
|
|
|
args[i] = mongoToV8Element( next );
|
2009-10-12 00:15:12 +02:00
|
|
|
}
|
2009-12-22 01:00:57 +01:00
|
|
|
setObject( "args", argsObject, true ); // for backwards compatibility
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2009-12-22 01:00:57 +01:00
|
|
|
_global->Set( v8::String::New( "args" ), v8::Undefined() );
|
2009-10-12 00:15:12 +02:00
|
|
|
}
|
2010-09-23 23:36:04 +02:00
|
|
|
if ( globalScriptEngine->interrupted() ) {
|
|
|
|
stringstream ss;
|
|
|
|
ss << "error in invoke: " << globalScriptEngine->checkInterrupt();
|
|
|
|
_error = ss.str();
|
|
|
|
log() << _error << endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
enableV8Interrupt(); // because of v8 locker we can check interrupted, then enable
|
2009-10-12 00:15:12 +02:00
|
|
|
Local<Value> result = ((v8::Function*)(*funcValue))->Call( _this , nargs , args.get() );
|
2010-09-23 23:36:04 +02:00
|
|
|
disableV8Interrupt();
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
if ( result.IsEmpty() ) {
|
2009-10-12 00:15:12 +02:00
|
|
|
stringstream ss;
|
2010-09-23 23:36:04 +02:00
|
|
|
if ( try_catch.HasCaught() && !try_catch.CanContinue() ) {
|
|
|
|
ss << "error in invoke: " << globalScriptEngine->checkInterrupt();
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2010-09-23 23:36:04 +02:00
|
|
|
ss << "error in invoke: " << toSTLString( &try_catch );
|
|
|
|
}
|
2009-10-12 00:15:12 +02:00
|
|
|
_error = ss.str();
|
|
|
|
log() << _error << endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( ! ignoreReturn ) {
|
2009-10-12 00:15:12 +02:00
|
|
|
_global->Set( v8::String::New( "return" ) , result );
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
bool V8Scope::exec( const StringData& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs ) {
|
|
|
|
if ( timeoutMs ) {
|
2009-10-11 04:24:08 +02:00
|
|
|
static bool t = 1;
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( t ) {
|
2010-08-26 03:59:32 +02:00
|
|
|
log() << "timeoutMs not support for v8 yet code: " << code << endl;
|
2009-10-11 04:24:08 +02:00
|
|
|
t = 0;
|
|
|
|
}
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-11 04:24:08 +02:00
|
|
|
TryCatch try_catch;
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
Handle<Script> script = v8::Script::Compile( v8::String::New( code.data() ) ,
|
|
|
|
v8::String::New( name.c_str() ) );
|
2009-10-11 04:24:08 +02:00
|
|
|
if (script.IsEmpty()) {
|
|
|
|
stringstream ss;
|
2009-10-12 00:15:12 +02:00
|
|
|
ss << "compile error: " << toSTLString( &try_catch );
|
2009-10-11 04:24:08 +02:00
|
|
|
_error = ss.str();
|
|
|
|
if (reportError)
|
2009-10-12 00:15:12 +02:00
|
|
|
log() << _error << endl;
|
2009-10-11 04:24:08 +02:00
|
|
|
if ( assertOnError )
|
2009-12-28 22:43:43 +01:00
|
|
|
uassert( 10233 , _error , 0 );
|
2009-10-11 04:24:08 +02:00
|
|
|
return false;
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
|
2010-09-23 23:36:04 +02:00
|
|
|
if ( globalScriptEngine->interrupted() ) {
|
|
|
|
_error = (string)"exec error: " + globalScriptEngine->checkInterrupt();
|
|
|
|
if ( reportError ) {
|
|
|
|
log() << _error << endl;
|
|
|
|
}
|
|
|
|
if ( assertOnError ) {
|
|
|
|
uassert( 13475 , _error , 0 );
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
enableV8Interrupt(); // because of v8 locker we can check interrupted, then enable
|
2009-10-11 04:24:08 +02:00
|
|
|
Handle<v8::Value> result = script->Run();
|
2010-09-23 23:36:04 +02:00
|
|
|
disableV8Interrupt();
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( result.IsEmpty() ) {
|
2010-09-23 23:36:04 +02:00
|
|
|
if ( try_catch.HasCaught() && !try_catch.CanContinue() ) {
|
|
|
|
_error = (string)"exec error: " + globalScriptEngine->checkInterrupt();
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
else {
|
2010-09-23 23:36:04 +02:00
|
|
|
_error = (string)"exec error: " + toSTLString( &try_catch );
|
|
|
|
}
|
2009-10-11 04:24:08 +02:00
|
|
|
if ( reportError )
|
2009-10-12 00:15:12 +02:00
|
|
|
log() << _error << endl;
|
2009-10-11 04:24:08 +02:00
|
|
|
if ( assertOnError )
|
2009-12-28 22:43:43 +01:00
|
|
|
uassert( 10234 , _error , 0 );
|
2009-10-11 04:24:08 +02:00
|
|
|
return false;
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
|
2009-10-13 16:48:38 +02:00
|
|
|
_global->Set( v8::String::New( "__lastres__" ) , result );
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( printResult && ! result->IsUndefined() ) {
|
2009-10-11 04:24:08 +02:00
|
|
|
cout << toSTLString( result ) << endl;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-10-11 04:24:08 +02:00
|
|
|
return true;
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
void V8Scope::injectNative( const char *field, NativeFunction func ) {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2010-09-08 06:32:14 +02:00
|
|
|
Handle< FunctionTemplate > f( newV8Function< nativeCallback >() );
|
2009-12-29 20:13:08 +01:00
|
|
|
f->Set( v8::String::New( "_native_function" ), External::New( (void*)func ) );
|
|
|
|
_global->Set( v8::String::New( field ), f->GetFunction() );
|
2011-01-04 06:40:41 +01:00
|
|
|
}
|
|
|
|
|
2009-12-22 20:39:23 +01:00
|
|
|
void V8Scope::gc() {
|
2010-07-05 06:54:17 +02:00
|
|
|
cout << "in gc" << endl;
|
2010-09-23 23:36:04 +02:00
|
|
|
V8Lock l;
|
2011-01-11 07:07:04 +01:00
|
|
|
while( !V8::IdleNotification() );
|
2009-12-22 20:39:23 +01:00
|
|
|
}
|
2009-10-11 04:24:08 +02:00
|
|
|
|
2009-10-13 16:12:44 +02:00
|
|
|
// ----- db access -----
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::localConnect( const char * dbName ) {
|
2010-09-09 08:30:25 +02:00
|
|
|
{
|
|
|
|
V8_SIMPLE_HEADER
|
|
|
|
|
|
|
|
if ( _connectState == EXTERNAL )
|
|
|
|
throw UserException( 12510, "externalSetup already called, can't call externalSetup" );
|
2011-01-04 06:40:41 +01:00
|
|
|
if ( _connectState == LOCAL ) {
|
2010-09-09 08:30:25 +02:00
|
|
|
if ( _localDBName == dbName )
|
|
|
|
return;
|
|
|
|
throw UserException( 12511, "localConnect called with a different name previously" );
|
|
|
|
}
|
2009-12-29 20:04:00 +01:00
|
|
|
|
2010-09-23 23:36:04 +02:00
|
|
|
// needed for killop / interrupt support
|
|
|
|
v8::Locker::StartPreemption( 50 );
|
|
|
|
|
2010-09-09 08:30:25 +02:00
|
|
|
//_global->Set( v8::String::New( "Mongo" ) , _engine->_externalTemplate->GetFunction() );
|
|
|
|
_global->Set( v8::String::New( "Mongo" ) , getMongoFunctionTemplate( true )->GetFunction() );
|
|
|
|
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;
|
2009-10-13 16:12:44 +02:00
|
|
|
}
|
2009-12-22 18:52:11 +01:00
|
|
|
loadStored();
|
2009-10-13 16:12:44 +02:00
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
|
|
|
void V8Scope::externalSetup() {
|
2009-12-29 20:13:08 +01:00
|
|
|
V8_SIMPLE_HEADER
|
2009-10-13 16:12:44 +02:00
|
|
|
if ( _connectState == EXTERNAL )
|
|
|
|
return;
|
|
|
|
if ( _connectState == LOCAL )
|
2009-12-29 20:32:09 +01:00
|
|
|
throw UserException( 12512, "localConnect already called, can't call externalSetup" );
|
2009-12-29 20:04:00 +01:00
|
|
|
|
2010-01-11 19:04:11 +01:00
|
|
|
installFork( _global, _context );
|
2009-10-13 22:12:43 +02:00
|
|
|
_global->Set( v8::String::New( "Mongo" ) , getMongoFunctionTemplate( false )->GetFunction() );
|
2010-08-10 20:35:02 +02:00
|
|
|
execCoreFiles();
|
2009-10-13 16:12:44 +02:00
|
|
|
_connectState = EXTERNAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----- internal -----
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::reset() {
|
2009-10-13 22:12:43 +02:00
|
|
|
_startCall();
|
2009-10-13 17:11:55 +02:00
|
|
|
}
|
|
|
|
|
2011-01-04 06:40:41 +01:00
|
|
|
void V8Scope::_startCall() {
|
2009-10-11 04:24:08 +02:00
|
|
|
_error = "";
|
|
|
|
}
|
2011-01-04 06:40:41 +01:00
|
|
|
|
2009-05-05 00:45:32 +02:00
|
|
|
} // namespace mongo
|