Spider Monkey: lots of work on property mangling

This commit is contained in:
Eliot Horowitz
2009-05-05 10:43:54 -04:00
parent 6f329f6694
commit 7c16a1476d
4 changed files with 295 additions and 179 deletions

View File

@@ -1,35 +1,13 @@
// engine_spidermonkey.cpp
#include "engine.h"
#ifdef _WIN32
#define XP_WIN
#else
#define XP_UNIX
#endif
#ifdef MOZJS
#include "mozjs/jsapi.h"
#else
#include "js/jsapi.h"
#endif
#include "engine_spidermonkey.h"
#include "../client/dbclient.h"
extern const char * jsconcatcode;
namespace mongo {
class SMScope;
void dontDeleteScope( SMScope * s ){}
boost::thread_specific_ptr<SMScope> currentScope( dontDeleteScope );
JSBool resolveBSONField( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp );
void errorReporter( JSContext *cx, const char *message, JSErrorReport *report );
static JSClass bson_ro_class = {
"bson_object" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE ,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
@@ -104,27 +82,42 @@ namespace mongo {
return 0;
}
private:
JSContext * _context;
};
// ------- object helpers ------
class ObjectWrapper {
public:
ObjectWrapper( JSContext * cx , JSObject * obj ) : _context( cx ) , _object( obj ){}
JSObject * getJSObject( const char * name ){
JSObject * getJSObject( JSObject * o , const char * name ){
jsval v;
assert( JS_GetProperty( _context , _object , name , &v ) );
assert( JS_GetProperty( _context , o , name , &v ) );
return JSVAL_TO_OBJECT( v );
}
JSObject * getGlobalObject( const char * name ){
return getJSObject( JS_GetGlobalObject( _context ) , name );
}
JSObject * getGlobalPrototype( const char * name ){
return getJSObject( getGlobalObject( name ) , "prototype" );
}
bool hasProperty( JSObject * o , const char * name ){
JSBool res;
assert( JS_HasProperty( _context , o , name , & res ) );
return res;
}
jsval getProperty( JSObject * o , const char * field ){
jsval v;
assert( JS_GetProperty( _context , o , field , &v ) );
return v;
}
void setProperty( JSObject * o , const char * field , jsval v ){
assert( JS_SetProperty( _context , o , field , &v ) );
}
private:
JSContext * _context;
JSObject * _object;
};
static JSClass global_class = {
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
@@ -145,8 +138,6 @@ namespace mongo {
return JS_TRUE;
}
JSBool native_db_create( JSContext * cx , JSObject * obj , uintN argc, jsval *argv, jsval *rval );
JSFunctionSpec globalHelpers[] = {
{ "print" , &native_print , 0 , 0 , 0 } ,
{ "createDB" , &native_db_create , 0 , 0 , 0 } ,
@@ -210,143 +201,6 @@ namespace mongo {
globalScriptEngine = globalSMEngine;
}
// ------ mongo stuff ------
JSBool mongo_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){
uassert( "mongo_constructor not implemented yet" , 0 );
throw -1;
}
JSBool mongo_local_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){
Convertor c( cx );
DBClientBase * client = createDirectClient();
JS_SetPrivate( cx , obj , (void*)client );
jsval host = c.toval( "EMBEDDED" );
assert( JS_SetProperty( cx , obj , "host" , &host ) );
return JS_TRUE;
}
void mongo_finalize( JSContext * cx , JSObject * obj ){
DBClientBase * client = (DBClientBase*)JS_GetPrivate( cx , obj );
if ( client ){
cout << "client x: " << client << endl;
cout << "Addr in finalize: " << client->getServerAddress() << endl;
delete client;
}
}
static JSClass mongo_class = {
"Mongo" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE ,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, mongo_finalize,
0 , 0 , 0 ,
mongo_constructor ,
0 , 0 , 0 , 0
};
static JSClass mongo_local_class = {
"Mongo" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE ,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, mongo_finalize,
0 , 0 , 0 ,
mongo_local_constructor ,
0 , 0 , 0 , 0
};
// -------------- DB ---------------
JSBool db_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){
cout << "db_constructor" << endl;
uassert( "wrong number of arguments to DB" , argc == 2 );
assert( JS_SetProperty( cx , obj , "_mongo" , &(argv[0]) ) );
assert( JS_SetProperty( cx , obj , "_name" , &(argv[1]) ) );
return JS_TRUE;
}
JSBool resolve_dbcollection( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp ){
Convertor c( cx );
string collname = c.toString( id );
if ( collname == "prototype" || collname.find( "__" ) == 0 ||
collname == "_mongo" || collname == "_name" )
return JS_TRUE;
JSObject * proto = JS_GetPrototype( cx , obj );
if ( proto ){
JSBool res;
assert( JS_HasProperty( cx , proto , collname.c_str() , &res ) );
if ( res )
return JS_TRUE;
}
uassert( (string)"not done: resolve_dbcollection: " + collname , 0 );
return JS_TRUE;
}
static JSClass db_class = {
"DB" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE ,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, (JSResolveOp)(&resolve_dbcollection) , JS_ConvertStub, JS_FinalizeStub,
0 , 0 , 0 ,
db_constructor ,
0 , 0 , 0 , 0
};
static JSPropertySpec db_props[] = {
{ "_mongo" , 0 , 0 } ,
{ "_name" , 0 , 0 } ,
{ 0 }
};
JSBool native_db_create( JSContext * cx , JSObject * obj , uintN argc, jsval *argv, jsval *rval ){
uassert( "db needs 2 args" , argc == 2 );
ObjectWrapper a( cx , JS_GetGlobalObject( cx ) );
JSObject * DB = a.getJSObject( "DB" );
ObjectWrapper b( cx , DB );
JSObject * DBprototype = b.getJSObject( "prototype" );
uassert( "can't find DB prototype" , DBprototype );
JSObject * db = JS_NewObject( cx , &db_class , 0 , 0 );
assert( JS_SetProperty( cx , db , "_mongo" , &(argv[0]) ) );
assert( JS_SetProperty( cx , db , "_name" , &(argv[1]) ) );
assert( JS_SetPrototype( cx , db , DBprototype ) );
*rval = OBJECT_TO_JSVAL( db );
return JS_TRUE;
}
// -------------- object id -------------
JSBool object_id_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){
OID oid;
if ( argc == 0 ){
oid.init();
}
else {
uassert( "object_id_constructor 2nd case" , 0 );
}
Convertor c( cx );
jsval v = c.toval( oid.str().c_str() );
assert( JS_SetProperty( cx , obj , "str" , &v ) );
return JS_TRUE;
}
static JSClass object_id_class = {
"ObjectId" , JSCLASS_HAS_PRIVATE ,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
0 , 0 , 0 ,
object_id_constructor ,
0 , 0 , 0 , 0
};
// ------ scope ------
@@ -396,7 +250,6 @@ namespace mongo {
void localConnect( const char * dbName ){
assert( JS_InitClass( _context , _global , 0 , &mongo_local_class , 0 , 0 , 0 , 0 , 0 , 0 ) );
assert( JS_InitClass( _context , _global , 0 , &object_id_class , 0 , 0 , 0 , 0 , 0 , 0 ) );
//assert( JS_InitClass( _context , _global , 0 , &db_class , 0 , 0 , db_props , 0 ,0 , 0 ) );
exec( jsconcatcode );
@@ -439,8 +292,7 @@ namespace mongo {
}
JSObject * getJSObject( const char * field ){
ObjectWrapper o( _context , _global );
return o.getJSObject( field );
return _convertor->getJSObject( _global , field );
}
int type( const char *field ){
@@ -590,10 +442,13 @@ namespace mongo {
void SMEngine::runTest(){
SMScope s;
s.localConnect( "blah" );
s.localConnect( "foo" );
s.exec( "print( '_mongo:' + _mongo );" );
s.exec( "assert( db.getMongo() )" );
s.exec( "assert( db.blah , 'collection getting does not work' ); " );
s.exec( "assert( db.bar , 'collection getting does not work' ); " );
s.exec( "db.bar.verify();" );
s.exec( "db.bar.silly.verify();" );
s.exec( "assert.eq( 'foo.bar.silly' , db.bar.silly._fullName )" );
}
Scope * SMEngine::createScope(){
@@ -602,3 +457,5 @@ namespace mongo {
}
#include "sm_db.cpp"