diff options
-rw-r--r-- | scripting/engine_spidermonkey.cpp | 116 |
1 files changed, 78 insertions, 38 deletions
diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp index 64fe21cd098..e857b90d138 100644 --- a/scripting/engine_spidermonkey.cpp +++ b/scripting/engine_spidermonkey.cpp @@ -47,6 +47,9 @@ namespace mongo { } }; + typedef std::map<long long, NativeFunction> FunctionMap; + typedef std::map<long long, void*> ArgumentMap; + string trim( string s ) { while ( s.size() && isspace( s[0] ) ) s = s.substr( 1 ); @@ -997,43 +1000,8 @@ namespace mongo { return JS_TRUE; } - JSBool native_helper( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ) { - Convertor c(cx); - - NativeFunction func = (NativeFunction)((long long)c.getNumber( obj , "x" ) ); - void* data = (void*)((long long)c.getNumber( obj , "y" ) ); - assert( func ); - - BSONObj a; - if ( argc > 0 ) { - BSONObjBuilder args; - for ( uintN i=0; i<argc; i++ ) { - c.append( args , args.numStr( i ) , argv[i] ); - } - - a = args.obj(); - } - - BSONObj out; - try { - out = func( a, data ); - } - catch ( std::exception& e ) { - JS_ReportError( cx , e.what() ); - return JS_FALSE; - } - - if ( out.isEmpty() ) { - *rval = JSVAL_VOID; - } - else { - *rval = c.toval( out.firstElement() ); - } - - return JS_TRUE; - } - JSBool native_load( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ); + JSBool native_helper( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ); JSBool native_gc( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ) { JS_GC( cx ); @@ -1611,11 +1579,17 @@ namespace mongo { void injectNative( const char *field, NativeFunction func, void* data ) { smlock; string name = field; - _convertor->setProperty( _global , (name + "_").c_str() , _convertor->toval( (double)(long long)func ) ); + long long funcId = static_cast<long long>(_functionMap.size()); + _functionMap.insert(make_pair(funcId, func)); + jsval v = _convertor->toval(funcId); + _convertor->setProperty(_global, (name + "_").c_str(), v); stringstream code; if (data) { - _convertor->setProperty( _global , (name + "_data_").c_str() , _convertor->toval( (double)(long long)data ) ); + long long argsId = static_cast<long long>(_argumentMap.size()); + _argumentMap.insert(make_pair(argsId, data)); + v = _convertor->toval(argsId); + _convertor->setProperty(_global, (name + "_data_").c_str(), v); code << field << "_" << " = { x : " << field << "_ , y: " << field << "_data_ }; "; } else { code << field << "_" << " = { x : " << field << "_ }; "; @@ -1631,6 +1605,10 @@ namespace mongo { JSContext *SavedContext() const { return _context; } + // map from internal function id to function pointer + FunctionMap _functionMap; + // map from internal function argument id to function pointer + ArgumentMap _argumentMap; private: void _postCreateHacks() { @@ -1696,7 +1674,69 @@ namespace mongo { return JS_TRUE; } + JSBool native_helper( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ) { + try { + Convertor c(cx); + + // get function pointer from JS caller's argument property 'x' + massert(16735, "nativeHelper argument requires object with 'x' property", + c.hasProperty(obj, "x")); + FunctionMap::iterator funcIter = + currentScope->_functionMap.find(static_cast<long long>(c.getNumber(obj, "x"))); + massert(16734, "JavaScript function not in map", + funcIter != currentScope->_functionMap.end()); + NativeFunction func = funcIter->second; + assert(func); + + // get data pointer from JS caller's argument property 'y' + void* data = NULL; + if (c.hasProperty(obj, "y")) { + ArgumentMap::iterator argIter = currentScope->_argumentMap.find( + static_cast<long long>(c.getNumber(obj, "y"))); + massert(16736, "nativeHelper 'y' parameter must be in the argumentMap", + argIter != currentScope->_argumentMap.end()); + data = argIter->second; + } + + BSONObj a; + if ( argc > 0 ) { + BSONObjBuilder args; + for ( uintN i = 0; i < argc; ++i ) { + c.append( args , args.numStr( i ) , argv[i] ); + } + a = args.obj(); + } + + BSONObj out; + try { + out = func( a, data ); + } + catch ( std::exception& e ) { + if ( ! JS_IsExceptionPending( cx ) ) { + JS_ReportError( cx, e.what() ); + } + return JS_FALSE; + } + if ( out.isEmpty() ) { + *rval = JSVAL_VOID; + } + else { + *rval = c.toval( out.firstElement() ); + } + } + catch ( const AssertionException& e ) { + if ( ! JS_IsExceptionPending( cx ) ) { + JS_ReportError( cx, e.what() ); + } + return JS_FALSE; + } + catch ( const std::exception& e ) { + log() << "unhandled exception: " << e.what() << ", throwing Fatal Assertion" << endl; + verifyFailed( 16281 ); + } + return JS_TRUE; + } void SMEngine::runTest() { SMScope s; |