summaryrefslogtreecommitdiff
path: root/scripting
diff options
context:
space:
mode:
authorAntonin Kral <a.kral@bobek.cz>2012-08-29 20:54:51 +0200
committerAntonin Kral <a.kral@bobek.cz>2012-08-29 20:54:51 +0200
commit83957b73f9177f6e38bd5375bd93ca1f6a47188c (patch)
treef20b7d6ac9a9c64ff5bb6b5910a24abbb356b1d5 /scripting
parent5071d203970edd4c995493d810abe20987e76fe9 (diff)
Imported Upstream version 2.2.0upstream/2.2.0
Diffstat (limited to 'scripting')
-rw-r--r--scripting/bench.cpp244
-rw-r--r--scripting/engine.cpp507
-rw-r--r--scripting/engine.h234
-rw-r--r--scripting/engine_java.cpp764
-rw-r--r--scripting/engine_java.h223
-rw-r--r--scripting/engine_none.cpp24
-rw-r--r--scripting/engine_spidermonkey.cpp1749
-rw-r--r--scripting/engine_spidermonkey.h105
-rw-r--r--scripting/engine_v8.cpp1547
-rw-r--r--scripting/engine_v8.h231
-rw-r--r--scripting/sm_db.cpp1240
-rw-r--r--scripting/utils.cpp77
-rw-r--r--scripting/v8_db.cpp1049
-rw-r--r--scripting/v8_db.h96
-rw-r--r--scripting/v8_utils.cpp291
-rw-r--r--scripting/v8_utils.h43
-rw-r--r--scripting/v8_wrapper.cpp99
-rw-r--r--scripting/v8_wrapper.h34
18 files changed, 0 insertions, 8557 deletions
diff --git a/scripting/bench.cpp b/scripting/bench.cpp
deleted file mode 100644
index 9ada7d6495c..00000000000
--- a/scripting/bench.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/** @file bench.cpp */
-
-/*
- * Copyright (C) 2010 10gen Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "pch.h"
-#include "engine.h"
-#include "../util/md5.hpp"
-#include "../util/version.h"
-#include "../client/dbclient.h"
-#include "../client/connpool.h"
-// ---------------------------------
-// ---- benchmarking system --------
-// ---------------------------------
-
-
-namespace mongo {
-
-
- struct BenchRunConfig {
- BenchRunConfig() {
- host = "localhost";
- db = "test";
-
- parallel = 1;
- seconds = 1;
-
- active = true;
- threadsReady = 0;
- error = false;
- }
-
- string host;
- string db;
-
- unsigned parallel;
- double seconds;
-
- BSONObj ops;
-
- bool active; // true at starts, gets set to false when should stop
- AtomicUInt threadsReady;
-
- bool error;
- };
-
- static bool _hasSpecial( const BSONObj& obj ) {
- BSONObjIterator i( obj );
- while ( i.more() ) {
- BSONElement e = i.next();
- if ( e.fieldName()[0] == '#' )
- return true;
-
- if ( ! e.isABSONObj() )
- continue;
-
- if ( _hasSpecial( e.Obj() ) )
- return true;
- }
- return false;
- }
-
- static void _fixField( BSONObjBuilder& b , const BSONElement& e ) {
- assert( e.type() == Object );
-
- BSONObj sub = e.Obj();
- assert( sub.nFields() == 1 );
-
- BSONElement f = sub.firstElement();
- if ( str::equals( "#RAND_INT" , f.fieldName() ) ) {
- BSONObjIterator i( f.Obj() );
- int min = i.next().numberInt();
- int max = i.next().numberInt();
-
- int x = min + ( rand() % ( max - min ) );
- b.append( e.fieldName() , x );
- }
- else {
- uasserted( 14811 , str::stream() << "invalid bench dynamic piece: " << f.fieldName() );
- }
-
- }
-
- static void fixQuery( BSONObjBuilder& b , const BSONObj& obj ) {
- BSONObjIterator i( obj );
- while ( i.more() ) {
- BSONElement e = i.next();
-
- if ( e.type() != Object ) {
- b.append( e );
- continue;
- }
-
- BSONObj sub = e.Obj();
- if ( sub.firstElement().fieldName()[0] != '#' ) {
- b.append( e );
- continue;
- }
-
- _fixField( b , e );
- }
- }
-
-
- static BSONObj fixQuery( const BSONObj& obj ) {
- if ( ! _hasSpecial( obj ) )
- return obj;
-
- BSONObjBuilder b( obj.objsize() + 128 );
- fixQuery( b , obj );
- return b.obj();
- }
-
- static void benchThread( BenchRunConfig * config ) {
- ScopedDbConnection conn( config->host );
- config->threadsReady++;
-
- while ( config->active ) {
- BSONObjIterator i( config->ops );
- while ( i.more() ) {
- BSONElement e = i.next();
- string ns = e["ns"].String();
- string op = e["op"].String();
-
- if ( op == "findOne" ) {
- conn->findOne( ns , fixQuery( e["query"].Obj() ) );
- }
- else if ( op == "remove" ) {
- conn->remove( ns , fixQuery( e["query"].Obj() ) );
- }
- else if ( op == "update" ) {
- conn->update( ns , fixQuery( e["query"].Obj() ) , e["update"].Obj() , e["upsert"].trueValue() );
- }
- else {
- log() << "don't understand op: " << op << endl;
- config->error = true;
- return;
- }
-
- }
- }
-
- conn.done();
- }
-
- /**
- * benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
- */
- BSONObj benchRun( const BSONObj& argsFake, void* data ) {
- assert( argsFake.firstElement().isABSONObj() );
- BSONObj args = argsFake.firstElement().Obj();
-
- // setup
-
- BenchRunConfig config;
-
- if ( args["host"].type() == String )
- config.host = args["host"].String();
- if ( args["db"].type() == String )
- config.db = args["db"].String();
-
- if ( args["parallel"].isNumber() )
- config.parallel = args["parallel"].numberInt();
- if ( args["seconds"].isNumber() )
- config.seconds = args["seconds"].number();
-
-
- config.ops = args["ops"].Obj();
-
- // execute
-
- ScopedDbConnection conn( config.host );
-
- // start threads
- vector<boost::thread*> all;
- for ( unsigned i=0; i<config.parallel; i++ )
- all.push_back( new boost::thread( boost::bind( benchThread , &config ) ) );
-
- // give them time to init
- while ( config.threadsReady < config.parallel )
- sleepmillis( 1 );
-
- BSONObj before;
- conn->simpleCommand( "admin" , &before , "serverStatus" );
-
- sleepmillis( (int)(1000.0 * config.seconds) );
-
- BSONObj after;
- conn->simpleCommand( "admin" , &after , "serverStatus" );
-
- conn.done();
-
- config.active = false;
-
- for ( unsigned i=0; i<all.size(); i++ )
- all[i]->join();
-
- if ( config.error )
- return BSON( "err" << 1 );
-
- // compute actual ops/sec
-
- before = before["opcounters"].Obj().copy();
- after = after["opcounters"].Obj().copy();
-
- bool totals = args["totals"].trueValue();
-
- BSONObjBuilder buf;
- if ( ! totals )
- buf.append( "note" , "values per second" );
-
- {
- BSONObjIterator i( after );
- while ( i.more() ) {
- BSONElement e = i.next();
- double x = e.number();
- x = x - before[e.fieldName()].number();
- if ( ! totals )
- x = x / config.seconds;
- buf.append( e.fieldName() , x );
- }
- }
- BSONObj zoo = buf.obj();
- return BSON( "" << zoo );
- }
-
- void installBenchmarkSystem( Scope& scope ) {
- scope.injectNative( "benchRun" , benchRun );
- }
-
-}
diff --git a/scripting/engine.cpp b/scripting/engine.cpp
deleted file mode 100644
index 7d13cb764fc..00000000000
--- a/scripting/engine.cpp
+++ /dev/null
@@ -1,507 +0,0 @@
-// engine.cpp
-
-/* 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.
- */
-
-#include "pch.h"
-#include "engine.h"
-#include "../util/file.h"
-#include "../client/dbclient.h"
-
-namespace mongo {
-
- long long Scope::_lastVersion = 1;
-
- int Scope::_numScopes = 0;
-
- Scope::Scope() : _localDBName("") , _loadedVersion(0), _numTimeUsed(0) {
- _numScopes++;
- }
-
- Scope::~Scope() {
- _numScopes--;
- }
-
- ScriptEngine::ScriptEngine() : _scopeInitCallback() {
- }
-
- ScriptEngine::~ScriptEngine() {
- }
-
- void Scope::append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName ) {
- int t = type( scopeName );
-
- switch ( t ) {
- case Object:
- builder.append( fieldName , getObject( scopeName ) );
- break;
- case Array:
- builder.appendArray( fieldName , getObject( scopeName ) );
- break;
- case NumberDouble:
- builder.append( fieldName , getNumber( scopeName ) );
- break;
- case NumberInt:
- builder.append( fieldName , getNumberInt( scopeName ) );
- break;
- case NumberLong:
- builder.append( fieldName , getNumberLongLong( scopeName ) );
- break;
- case String:
- builder.append( fieldName , getString( scopeName ).c_str() );
- break;
- case Bool:
- builder.appendBool( fieldName , getBoolean( scopeName ) );
- break;
- case jstNULL:
- case Undefined:
- builder.appendNull( fieldName );
- break;
- case Date:
- // TODO: make signed
- builder.appendDate( fieldName , Date_t((unsigned long long)getNumber( scopeName )) );
- break;
- case Code:
- builder.appendCode( fieldName , getString( scopeName ) );
- break;
- default:
- stringstream temp;
- temp << "can't append type from:";
- temp << t;
- uassert( 10206 , temp.str() , 0 );
- }
-
- }
-
- 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, recv, timeoutMs );
- }
-
- bool Scope::execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs ) {
-
- path p( filename );
-
- if ( ! exists( p ) ) {
- log() << "file [" << filename << "] doesn't exist" << endl;
- if ( assertOnError )
- assert( 0 );
- return false;
- }
-
- // iterate directories and recurse using all *.js files in the directory
- if ( is_directory( p ) ) {
- directory_iterator end;
- bool empty = true;
- for (directory_iterator it (p); it != end; it++) {
- empty = false;
- path sub (*it);
- if (!endsWith(sub.string().c_str(), ".js"))
- continue;
- if (!execFile(sub.string().c_str(), printResult, reportError, assertOnError, timeoutMs))
- return false;
- }
-
- if (empty) {
- log() << "directory [" << filename << "] doesn't have any *.js files" << endl;
- if ( assertOnError )
- assert( 0 );
- return false;
- }
-
- return true;
- }
-
- File f;
- f.open( filename.c_str() , true );
-
- unsigned L;
- {
- fileofs fo = f.len();
- assert( fo <= 0x7ffffffe );
- L = (unsigned) fo;
- }
- boost::scoped_array<char> data (new char[L+1]);
- data[L] = 0;
- f.read( 0 , data.get() , L );
-
- int offset = 0;
- if (data[0] == '#' && data[1] == '!') {
- const char* newline = strchr(data.get(), '\n');
- if (! newline)
- return true; // file of just shebang treated same as empty file
- offset = newline - data.get();
- }
-
- StringData code (data.get() + offset, L - offset);
-
- return exec( code , filename , printResult , reportError , assertOnError, timeoutMs );
- }
-
- void Scope::storedFuncMod() {
- _lastVersion++;
- }
-
- void Scope::validateObjectIdString( const string &str ) {
- massert( 10448 , "invalid object id: length", str.size() == 24 );
-
- for ( string::size_type i=0; i<str.size(); i++ ) {
- char c = str[i];
- if ( ( c >= '0' && c <= '9' ) ||
- ( c >= 'a' && c <= 'f' ) ||
- ( c >= 'A' && c <= 'F' ) ) {
- continue;
- }
- massert( 10430 , "invalid object id: not hex", false );
- }
- }
-
- void Scope::loadStored( bool ignoreNotConnected ) {
- if ( _localDBName.size() == 0 ) {
- if ( ignoreNotConnected )
- return;
- uassert( 10208 , "need to have locallyConnected already" , _localDBName.size() );
- }
- if ( _loadedVersion == _lastVersion )
- return;
-
- _loadedVersion = _lastVersion;
-
- string coll = _localDBName + ".system.js";
-
- static DBClientBase * db = createDirectClient();
- auto_ptr<DBClientCursor> c = db->query( coll , Query(), 0, 0, NULL, QueryOption_SlaveOk, 0 );
- assert( c.get() );
-
- set<string> thisTime;
-
- while ( c->more() ) {
- BSONObj o = c->nextSafe();
-
- BSONElement n = o["_id"];
- BSONElement v = o["value"];
-
- uassert( 10209 , str::stream() << "name has to be a string: " << n , n.type() == String );
- uassert( 10210 , "value has to be set" , v.type() != EOO );
-
- setElement( n.valuestr() , v );
-
- thisTime.insert( n.valuestr() );
- _storedNames.insert( n.valuestr() );
-
- }
-
- // --- remove things from scope that were removed
-
- list<string> toremove;
-
- for ( set<string>::iterator i=_storedNames.begin(); i!=_storedNames.end(); i++ ) {
- string n = *i;
- if ( thisTime.count( n ) == 0 )
- toremove.push_back( n );
- }
-
- for ( list<string>::iterator i=toremove.begin(); i!=toremove.end(); i++ ) {
- string n = *i;
- _storedNames.erase( n );
- execSetup( (string)"delete " + n , "clean up scope" );
- }
-
- }
-
- ScriptingFunction Scope::createFunction( const char * code ) {
- if ( code[0] == '/' && code [1] == '*' ) {
- code += 2;
- while ( code[0] && code[1] ) {
- if ( code[0] == '*' && code[1] == '/' ) {
- code += 2;
- break;
- }
- code++;
- }
- }
- map<string,ScriptingFunction>::iterator i = _cachedFunctions.find( code );
- if ( i != _cachedFunctions.end() )
- return i->second;
- ScriptingFunction f = _createFunction( code );
- _cachedFunctions[code] = f;
- return f;
- }
-
- namespace JSFiles {
- extern const JSFile collection;
- extern const JSFile db;
- extern const JSFile mongo;
- extern const JSFile mr;
- extern const JSFile query;
- extern const JSFile utils;
- extern const JSFile utils_sh;
- }
-
- void Scope::execCoreFiles() {
- // keeping same order as in SConstruct
- execSetup(JSFiles::utils);
- execSetup(JSFiles::utils_sh);
- execSetup(JSFiles::db);
- execSetup(JSFiles::mongo);
- execSetup(JSFiles::mr);
- execSetup(JSFiles::query);
- execSetup(JSFiles::collection);
- }
-
- typedef map< string , list<Scope*> > PoolToScopes;
-
- class ScopeCache {
- public:
-
- ScopeCache() : _mutex("ScopeCache") {
- _magic = 17;
- }
-
- ~ScopeCache() {
- assert( _magic == 17 );
- _magic = 1;
-
- if ( inShutdown() )
- return;
-
- clear();
- }
-
- void done( const string& pool , Scope * s ) {
- scoped_lock lk( _mutex );
- list<Scope*> & l = _pools[pool];
- // make we dont keep to many contexts, or use them for too long
- if ( l.size() > 10 || s->getTimeUsed() > 100 ) {
- delete s;
- }
- else {
- l.push_back( s );
- s->reset();
- }
- }
-
- Scope * get( const string& pool ) {
- scoped_lock lk( _mutex );
- list<Scope*> & l = _pools[pool];
- if ( l.size() == 0 )
- return 0;
-
- Scope * s = l.back();
- l.pop_back();
- s->reset();
- s->incTimeUsed();
- return s;
- }
-
- void clear() {
- set<Scope*> seen;
-
- for ( PoolToScopes::iterator i=_pools.begin() ; i != _pools.end(); i++ ) {
- for ( list<Scope*>::iterator j=i->second.begin(); j != i->second.end(); j++ ) {
- Scope * s = *j;
- assert( ! seen.count( s ) );
- delete s;
- seen.insert( s );
- }
- }
-
- _pools.clear();
- }
-
- private:
- PoolToScopes _pools;
- mongo::mutex _mutex;
- int _magic;
- };
-
- thread_specific_ptr<ScopeCache> scopeCache;
-
- class PooledScope : public Scope {
- public:
- PooledScope( const string pool , Scope * real ) : _pool( pool ) , _real( real ) {
- _real->loadStored( true );
- };
- virtual ~PooledScope() {
- ScopeCache * sc = scopeCache.get();
- if ( sc ) {
- sc->done( _pool , _real );
- _real = 0;
- }
- else {
- // this means that the Scope was killed from a different thread
- // for example a cursor got timed out that has a $where clause
- log(3) << "warning: scopeCache is empty!" << endl;
- delete _real;
- _real = 0;
- }
- }
-
- void reset() {
- _real->reset();
- }
- void init( const BSONObj * data ) {
- _real->init( data );
- }
-
- void localConnect( const char * dbName ) {
- _real->localConnect( dbName );
- }
- void externalSetup() {
- _real->externalSetup();
- }
-
- double getNumber( const char *field ) {
- return _real->getNumber( field );
- }
- string getString( const char *field ) {
- return _real->getString( field );
- }
- bool getBoolean( const char *field ) {
- return _real->getBoolean( field );
- }
- BSONObj getObject( const char *field ) {
- return _real->getObject( field );
- }
-
- int type( const char *field ) {
- return _real->type( field );
- }
-
- void setElement( const char *field , const BSONElement& val ) {
- _real->setElement( field , val );
- }
- void setNumber( const char *field , double val ) {
- _real->setNumber( field , val );
- }
- void setString( const char *field , const char * val ) {
- _real->setString( field , val );
- }
- void setObject( const char *field , const BSONObj& obj , bool readOnly=true ) {
- _real->setObject( field , obj , readOnly );
- }
- void setBoolean( const char *field , bool val ) {
- _real->setBoolean( field , val );
- }
-// void setThis( const BSONObj * obj ) {
-// _real->setThis( obj );
-// }
-
- void setFunction( const char *field , const char * code ) {
- _real->setFunction(field, code);
- }
-
- ScriptingFunction createFunction( const char * code ) {
- return _real->createFunction( code );
- }
-
- ScriptingFunction _createFunction( const char * code ) {
- return _real->createFunction( code );
- }
-
- void rename( const char * from , const char * to ) {
- _real->rename( from , to );
- }
-
- /**
- * @return 0 on success
- */
- int invoke( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs , bool ignoreReturn, bool readOnlyArgs, bool readOnlyRecv ) {
- return _real->invoke( func , args , recv, timeoutMs , ignoreReturn );
- }
-
- string getError() {
- return _real->getError();
- }
-
- bool exec( const StringData& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) {
- return _real->exec( code , name , printResult , reportError , assertOnError , timeoutMs );
- }
- bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) {
- return _real->execFile( filename , printResult , reportError , assertOnError , timeoutMs );
- }
-
- void injectNative( const char *field, NativeFunction func, void* data ) {
- _real->injectNative( field , func, data );
- }
-
- void gc() {
- _real->gc();
- }
-
- void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName ) {
- _real->append(builder, fieldName, scopeName);
- }
-
- private:
- string _pool;
- Scope * _real;
- };
-
- auto_ptr<Scope> ScriptEngine::getPooledScope( const string& pool ) {
- if ( ! scopeCache.get() ) {
- scopeCache.reset( new ScopeCache() );
- }
-
- Scope * s = scopeCache->get( pool );
- if ( ! s ) {
- s = newScope();
- }
-
- auto_ptr<Scope> p;
- p.reset( new PooledScope( pool , s ) );
- return p;
- }
-
- void ScriptEngine::threadDone() {
- ScopeCache * sc = scopeCache.get();
- if ( sc ) {
- sc->clear();
- }
- }
-
- void ( *ScriptEngine::_connectCallback )( DBClientWithCommands & ) = 0;
- const char * ( *ScriptEngine::_checkInterruptCallback )() = 0;
- unsigned ( *ScriptEngine::_getInterruptSpecCallback )() = 0;
-
- ScriptEngine * globalScriptEngine = 0;
-
- bool hasJSReturn( const string& code ) {
- size_t x = code.find( "return" );
- if ( x == string::npos )
- return false;
-
- return
- ( x == 0 || ! isalpha( code[x-1] ) ) &&
- ! isalpha( code[x+6] );
- }
-
- const char * jsSkipWhiteSpace( const char * raw ) {
- while ( raw[0] ) {
- while (isspace(*raw)) {
- raw++;
- }
-
- if ( raw[0] != '/' || raw[1] != '/' )
- break;
-
- while ( raw[0] && raw[0] != '\n' )
- raw++;
- }
- return raw;
- }
-}
-
diff --git a/scripting/engine.h b/scripting/engine.h
deleted file mode 100644
index 9dd5f1d322c..00000000000
--- a/scripting/engine.h
+++ /dev/null
@@ -1,234 +0,0 @@
-// engine.h
-
-/* 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.
- */
-
-#pragma once
-
-#include "../pch.h"
-#include "../db/jsobj.h"
-
-namespace mongo {
-
- struct JSFile {
- const char* name;
- const StringData& source;
- };
-
- typedef unsigned long long ScriptingFunction;
- typedef BSONObj (*NativeFunction) ( const BSONObj &args, void* data );
-
- class Scope : boost::noncopyable {
- public:
- Scope();
- virtual ~Scope();
-
- virtual void reset() = 0;
- virtual void init( const BSONObj * data ) = 0;
- void init( const char * data ) {
- BSONObj o( data );
- init( &o );
- }
-
- virtual void localConnect( const char * dbName ) = 0;
- virtual void externalSetup() = 0;
-
- class NoDBAccess {
- Scope * _s;
- public:
- NoDBAccess( Scope * s ) {
- _s = s;
- }
- ~NoDBAccess() {
- _s->rename( "____db____" , "db" );
- }
- };
- NoDBAccess disableDBAccess( const char * why ) {
- rename( "db" , "____db____" );
- return NoDBAccess( this );
- }
-
- virtual double getNumber( const char *field ) = 0;
- virtual int getNumberInt( const char *field ) { return (int)getNumber( field ); }
- virtual long long getNumberLongLong( const char *field ) { return (long long)getNumber( field ); }
- virtual string getString( const char *field ) = 0;
- virtual bool getBoolean( const char *field ) = 0;
- virtual BSONObj getObject( const char *field ) = 0;
-
- virtual int type( const char *field ) = 0;
-
- virtual void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName );
-
- virtual void setElement( const char *field , const BSONElement& e ) = 0;
- virtual void setNumber( const char *field , double val ) = 0;
- 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 setFunction( const char *field , const char * code ) = 0;
-// virtual void setThis( const BSONObj * obj ) = 0;
-
- virtual ScriptingFunction createFunction( const char * code );
-
- virtual void rename( const char * from , const char * to ) = 0;
- /**
- * @return 0 on success
- */
- virtual int invoke( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool readOnlyArgs = false, bool readOnlyRecv = false ) = 0;
- void invokeSafe( ScriptingFunction func , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0, bool readOnlyArgs = false, bool readOnlyRecv = false ) {
- int res = invoke( func , args , recv, timeoutMs, readOnlyArgs, readOnlyRecv );
- if ( res == 0 )
- return;
- throw UserException( 9004 , (string)"invoke failed: " + getError() );
- }
- virtual string getError() = 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() );
- }
-
- virtual bool exec( const StringData& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) = 0;
- virtual void execSetup( const StringData& code , const string& name = "setup" ) {
- exec( code , name , false , true , true , 0 );
- }
-
- void execSetup( const JSFile& file) {
- execSetup(file.source, file.name);
- }
-
- void execCoreFiles();
-
- virtual bool execFile( const string& filename , bool printResult , bool reportError , bool assertOnError, int timeoutMs = 0 );
-
- virtual void injectNative( const char *field, NativeFunction func, void* data = 0 ) = 0;
-
- virtual void gc() = 0;
-
- void loadStored( bool ignoreNotConnected = false );
-
- /**
- if any changes are made to .system.js, call this
- right now its just global - slightly inefficient, but a lot simpler
- */
- static void storedFuncMod();
-
- static int getNumScopes() {
- return _numScopes;
- }
-
- static void validateObjectIdString( const string &str );
-
- /** increments the number of times a scope was used */
- void incTimeUsed() { ++_numTimeUsed; }
- /** gets the number of times a scope was used */
- int getTimeUsed() { return _numTimeUsed; }
-
- protected:
-
- virtual ScriptingFunction _createFunction( const char * code ) = 0;
-
- string _localDBName;
- long long _loadedVersion;
- set<string> _storedNames;
- static long long _lastVersion;
- map<string,ScriptingFunction> _cachedFunctions;
- int _numTimeUsed;
-
- static int _numScopes;
- };
-
- void installGlobalUtils( Scope& scope );
-
- class DBClientWithCommands;
-
- class ScriptEngine : boost::noncopyable {
- public:
- ScriptEngine();
- virtual ~ScriptEngine();
-
- virtual Scope * newScope() {
- Scope *s = createScope();
- if ( s && _scopeInitCallback )
- _scopeInitCallback( *s );
- installGlobalUtils( *s );
- return s;
- }
-
- virtual void runTest() = 0;
-
- virtual bool utf8Ok() const = 0;
-
- static void setup();
-
- /** gets a scope from the pool or a new one if pool is empty
- * @param pool An identifier for the pool, usually the db name
- * @return the scope */
- auto_ptr<Scope> getPooledScope( const string& pool );
-
- /** call this method to release some JS resources when a thread is done */
- void threadDone();
-
- struct Unlocker { virtual ~Unlocker() {} };
- virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< Unlocker >( new Unlocker ); }
-
- void setScopeInitCallback( void ( *func )( Scope & ) ) { _scopeInitCallback = func; }
- static void setConnectCallback( void ( *func )( DBClientWithCommands& ) ) { _connectCallback = func; }
- static void runConnectCallback( DBClientWithCommands &c ) {
- if ( _connectCallback )
- _connectCallback( c );
- }
-
- // engine implementation may either respond to interrupt events or
- // poll for interrupts
-
- // the interrupt functions must not wait indefinitely on a lock
- virtual void interrupt( unsigned opSpec ) {}
- virtual void interruptAll() {}
-
- static void setGetInterruptSpecCallback( unsigned ( *func )() ) { _getInterruptSpecCallback = func; }
- static bool haveGetInterruptSpecCallback() { return _getInterruptSpecCallback; }
- static unsigned getInterruptSpec() {
- massert( 13474, "no _getInterruptSpecCallback", _getInterruptSpecCallback );
- return _getInterruptSpecCallback();
- }
-
- static void setCheckInterruptCallback( const char * ( *func )() ) { _checkInterruptCallback = func; }
- static bool haveCheckInterruptCallback() { return _checkInterruptCallback; }
- static const char * checkInterrupt() {
- return _checkInterruptCallback ? _checkInterruptCallback() : "";
- }
- static bool interrupted() {
- const char *r = checkInterrupt();
- return r && r[ 0 ];
- }
-
- protected:
- virtual Scope * createScope() = 0;
-
- private:
- void ( *_scopeInitCallback )( Scope & );
- static void ( *_connectCallback )( DBClientWithCommands & );
- static const char * ( *_checkInterruptCallback )();
- static unsigned ( *_getInterruptSpecCallback )();
- };
-
- bool hasJSReturn( const string& s );
-
- const char * jsSkipWhiteSpace( const char * raw );
-
- extern ScriptEngine * globalScriptEngine;
-}
diff --git a/scripting/engine_java.cpp b/scripting/engine_java.cpp
deleted file mode 100644
index 57388166e98..00000000000
--- a/scripting/engine_java.cpp
+++ /dev/null
@@ -1,764 +0,0 @@
-// java.cpp
-
-/* 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.
- */
-
-
-#include "pch.h"
-#include "engine_java.h"
-#include <iostream>
-#include <map>
-#include <list>
-
-#include "../db/jsobj.h"
-#include "../db/db.h"
-
-using namespace boost::filesystem;
-
-namespace mongo {
-
-//#define JNI_DEBUG 1
-
-#ifdef JNI_DEBUG
-#undef JNI_DEBUG
-#define JNI_DEBUG(x) cout << x << endl
-#else
-#undef JNI_DEBUG
-#define JNI_DEBUG(x)
-#endif
-
-} // namespace mongo
-
-
-
-#include "../util/net/message.h"
-#include "../db/db.h"
-
-using namespace std;
-
-namespace mongo {
-
-#if defined(_WIN32)
- /* [dm] this being undefined without us adding it here means there is
- no tss cleanup on windows for boost lib?
- we don't care for now esp on windows only
-
- the boost source says:
-
- This function's sole purpose is to cause a link error in cases where
- automatic tss cleanup is not implemented by Boost.Threads as a
- reminder that user code is responsible for calling the necessary
- functions at the appropriate times (and for implementing an a
- tss_cleanup_implemented() function to eliminate the linker's
- missing symbol error).
-
- If Boost.Threads later implements automatic tss cleanup in cases
- where it currently doesn't (which is the plan), the duplicate
- symbol error will warn the user that their custom solution is no
- longer needed and can be removed.
- */
- extern "C" void tss_cleanup_implemented(void) {
- //out() << "tss_cleanup_implemented called" << endl;
- }
-#endif
-
- JavaJSImpl * JavaJS = 0;
- extern string dbExecCommand;
-
-#if !defined(NOJNI)
-
- void myJNIClean( JNIEnv * env ) {
- JavaJS->detach( env );
- }
-
-#if defined(_WIN32)
- const char SYSTEM_COLON = ';';
-#else
- const char SYSTEM_COLON = ':';
-#endif
-
-
- void _addClassPath( const char * ed , stringstream & ss , const char * subdir ) {
- path includeDir(ed);
- includeDir /= subdir;
- directory_iterator end;
- try {
- directory_iterator i(includeDir);
- while ( i != end ) {
- path p = *i;
- ss << SYSTEM_COLON << p.string();
- i++;
- }
- }
- catch (...) {
- problem() << "exception looking for ed class path includeDir: " << includeDir.string() << endl;
- sleepsecs(3);
- dbexit( EXIT_JAVA );
- }
- }
-
-
- JavaJSImpl::JavaJSImpl(const char *appserverPath) {
- _jvm = 0;
- _mainEnv = 0;
- _dbhook = 0;
-
- stringstream ss;
- string edTemp;
-
- const char * ed = 0;
- ss << "-Djava.class.path=.";
-
- if ( appserverPath ) {
- ed = findEd(appserverPath);
- assert( ed );
-
- ss << SYSTEM_COLON << ed << "/build/";
-
- _addClassPath( ed , ss , "include" );
- _addClassPath( ed , ss , "include/jython/" );
- _addClassPath( ed , ss , "include/jython/javalib" );
- }
- else {
- const string jars = findJars();
- _addClassPath( jars.c_str() , ss , "jars" );
-
- edTemp += (string)jars + "/jars/mongojs-js.jar";
- ed = edTemp.c_str();
- }
-
-
-
-#if defined(_WIN32)
- ss << SYSTEM_COLON << "C:\\Program Files\\Java\\jdk\\lib\\tools.jar";
-#else
- ss << SYSTEM_COLON << "/opt/java/lib/tools.jar";
-#endif
-
- if ( getenv( "CLASSPATH" ) )
- ss << SYSTEM_COLON << getenv( "CLASSPATH" );
-
- string s = ss.str();
- char * p = (char *)malloc( s.size() * 4 );
- strcpy( p , s.c_str() );
- char *q = p;
-#if defined(_WIN32)
- while ( *p ) {
- if ( *p == '/' ) *p = '\\';
- p++;
- }
-#endif
-
- log(1) << "classpath: " << q << endl;
-
- JavaVMOption * options = new JavaVMOption[4];
- options[0].optionString = q;
- options[1].optionString = (char*)"-Djava.awt.headless=true";
- options[2].optionString = (char*)"-Xmx300m";
-
- // Prevent JVM from using async signals internally, since on linux the pre-installed handlers for these
- // signals don't seem to be respected by JNI.
- options[3].optionString = (char*)"-Xrs";
- // -Xcheck:jni
-
- _vmArgs = new JavaVMInitArgs();
- _vmArgs->version = JNI_VERSION_1_4;
- _vmArgs->options = options;
- _vmArgs->nOptions = 4;
- _vmArgs->ignoreUnrecognized = JNI_FALSE;
-
- log(1) << "loading JVM" << endl;
- jint res = JNI_CreateJavaVM( &_jvm, (void**)&_mainEnv, _vmArgs );
-
- if ( res ) {
- log() << "using classpath: " << q << endl;
- log()
- << " res : " << (unsigned) res << " "
- << "_jvm : " << _jvm << " "
- << "_env : " << _mainEnv << " "
- << endl;
- problem() << "Couldn't create JVM res:" << (int) res << " terminating" << endl;
- log() << "(try --nojni if you do not require that functionality)" << endl;
- exit(22);
- }
- jassert( res == 0 );
- jassert( _jvm > 0 );
- jassert( _mainEnv > 0 );
-
- _envs = new boost::thread_specific_ptr<JNIEnv>( myJNIClean );
- assert( ! _envs->get() );
- _envs->reset( _mainEnv );
-
- _dbhook = findClass( "ed/db/JSHook" );
- if ( _dbhook == 0 ) {
- log() << "using classpath: " << q << endl;
- printException();
- }
- jassert( _dbhook );
-
- if ( ed ) {
- jmethodID init = _mainEnv->GetStaticMethodID( _dbhook , "init" , "(Ljava/lang/String;)V" );
- jassert( init );
- _mainEnv->CallStaticVoidMethod( _dbhook , init , _getEnv()->NewStringUTF( ed ) );
- }
-
- _dbjni = findClass( "ed/db/DBJni" );
- jassert( _dbjni );
-
- _scopeCreate = _mainEnv->GetStaticMethodID( _dbhook , "scopeCreate" , "()J" );
- _scopeInit = _mainEnv->GetStaticMethodID( _dbhook , "scopeInit" , "(JLjava/nio/ByteBuffer;)Z" );
- _scopeSetThis = _mainEnv->GetStaticMethodID( _dbhook , "scopeSetThis" , "(JLjava/nio/ByteBuffer;)Z" );
- _scopeReset = _mainEnv->GetStaticMethodID( _dbhook , "scopeReset" , "(J)Z" );
- _scopeFree = _mainEnv->GetStaticMethodID( _dbhook , "scopeFree" , "(J)V" );
-
- _scopeGetNumber = _mainEnv->GetStaticMethodID( _dbhook , "scopeGetNumber" , "(JLjava/lang/String;)D" );
- _scopeGetString = _mainEnv->GetStaticMethodID( _dbhook , "scopeGetString" , "(JLjava/lang/String;)Ljava/lang/String;" );
- _scopeGetBoolean = _mainEnv->GetStaticMethodID( _dbhook , "scopeGetBoolean" , "(JLjava/lang/String;)Z" );
- _scopeGetType = _mainEnv->GetStaticMethodID( _dbhook , "scopeGetType" , "(JLjava/lang/String;)B" );
- _scopeGetObject = _mainEnv->GetStaticMethodID( _dbhook , "scopeGetObject" , "(JLjava/lang/String;Ljava/nio/ByteBuffer;)I" );
- _scopeGuessObjectSize = _mainEnv->GetStaticMethodID( _dbhook , "scopeGuessObjectSize" , "(JLjava/lang/String;)J" );
-
- _scopeSetNumber = _mainEnv->GetStaticMethodID( _dbhook , "scopeSetNumber" , "(JLjava/lang/String;D)Z" );
- _scopeSetBoolean = _mainEnv->GetStaticMethodID( _dbhook , "scopeSetBoolean" , "(JLjava/lang/String;Z)Z" );
- _scopeSetString = _mainEnv->GetStaticMethodID( _dbhook , "scopeSetString" , "(JLjava/lang/String;Ljava/lang/String;)Z" );
- _scopeSetObject = _mainEnv->GetStaticMethodID( _dbhook , "scopeSetObject" , "(JLjava/lang/String;Ljava/nio/ByteBuffer;)Z" );
-
- _functionCreate = _mainEnv->GetStaticMethodID( _dbhook , "functionCreate" , "(Ljava/lang/String;)J" );
- _invoke = _mainEnv->GetStaticMethodID( _dbhook , "invoke" , "(JJ)I" );
-
- jassert( _scopeCreate );
- jassert( _scopeInit );
- jassert( _scopeSetThis );
- jassert( _scopeReset );
- jassert( _scopeFree );
-
- jassert( _scopeGetNumber );
- jassert( _scopeGetString );
- jassert( _scopeGetObject );
- jassert( _scopeGetBoolean );
- jassert( _scopeGetType );
- jassert( _scopeGuessObjectSize );
-
- jassert( _scopeSetNumber );
- jassert( _scopeSetBoolean );
- jassert( _scopeSetString );
- jassert( _scopeSetObject );
-
- jassert( _functionCreate );
- jassert( _invoke );
-
- JNINativeMethod * nativeSay = new JNINativeMethod();
- nativeSay->name = (char*)"native_say";
- nativeSay->signature = (char*)"(Ljava/nio/ByteBuffer;)V";
- nativeSay->fnPtr = (void*)java_native_say;
- _mainEnv->RegisterNatives( _dbjni , nativeSay , 1 );
-
-
- JNINativeMethod * nativeCall = new JNINativeMethod();
- nativeCall->name = (char*)"native_call";
- nativeCall->signature = (char*)"(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I";
- nativeCall->fnPtr = (void*)java_native_call;
- _mainEnv->RegisterNatives( _dbjni , nativeCall , 1 );
-
- }
-
- JavaJSImpl::~JavaJSImpl() {
- if ( _jvm ) {
- _jvm->DestroyJavaVM();
- cout << "Destroying JVM" << endl;
- }
- }
-
-// scope
-
- jlong JavaJSImpl::scopeCreate() {
- return _getEnv()->CallStaticLongMethod( _dbhook , _scopeCreate );
- }
-
- jboolean JavaJSImpl::scopeReset( jlong id ) {
- return _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeReset );
- }
-
- void JavaJSImpl::scopeFree( jlong id ) {
- _getEnv()->CallStaticVoidMethod( _dbhook , _scopeFree , id );
- }
-
-// scope setters
-
- int JavaJSImpl::scopeSetBoolean( jlong id , const char * field , jboolean val ) {
- jstring fieldString = _getEnv()->NewStringUTF( field );
- int res = _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeSetNumber , id , fieldString , val );
- _getEnv()->DeleteLocalRef( fieldString );
- return res;
- }
-
- int JavaJSImpl::scopeSetNumber( jlong id , const char * field , double val ) {
- jstring fieldString = _getEnv()->NewStringUTF( field );
- int res = _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeSetNumber , id , fieldString , val );
- _getEnv()->DeleteLocalRef( fieldString );
- return res;
- }
-
- int JavaJSImpl::scopeSetString( jlong id , const char * field , const char * val ) {
- jstring s1 = _getEnv()->NewStringUTF( field );
- jstring s2 = _getEnv()->NewStringUTF( val );
- int res = _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeSetString , id , s1 , s2 );
- _getEnv()->DeleteLocalRef( s1 );
- _getEnv()->DeleteLocalRef( s2 );
- return res;
- }
-
- int JavaJSImpl::scopeSetObject( jlong id , const char * field , const BSONObj * obj ) {
- jobject bb = 0;
- if ( obj ) {
- bb = _getEnv()->NewDirectByteBuffer( (void*)(obj->objdata()) , (jlong)(obj->objsize()) );
- jassert( bb );
- }
-
- jstring s1 = _getEnv()->NewStringUTF( field );
- int res = _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeSetObject , id , s1 , bb );
- _getEnv()->DeleteLocalRef( s1 );
- if ( bb )
- _getEnv()->DeleteLocalRef( bb );
-
- return res;
- }
-
- int JavaJSImpl::scopeInit( jlong id , const BSONObj * obj ) {
- if ( ! obj )
- return 0;
-
- jobject bb = _getEnv()->NewDirectByteBuffer( (void*)(obj->objdata()) , (jlong)(obj->objsize()) );
- jassert( bb );
-
- int res = _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeInit , id , bb );
- _getEnv()->DeleteLocalRef( bb );
- return res;
- }
-
- int JavaJSImpl::scopeSetThis( jlong id , const BSONObj * obj ) {
- if ( ! obj )
- return 0;
-
- jobject bb = _getEnv()->NewDirectByteBuffer( (void*)(obj->objdata()) , (jlong)(obj->objsize()) );
- jassert( bb );
-
- int res = _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeSetThis , id , bb );
- _getEnv()->DeleteLocalRef( bb );
- return res;
- }
-
-// scope getters
-
- char JavaJSImpl::scopeGetType( jlong id , const char * field ) {
- jstring s1 = _getEnv()->NewStringUTF( field );
- int res =_getEnv()->CallStaticByteMethod( _dbhook , _scopeGetType , id , s1 );
- _getEnv()->DeleteLocalRef( s1 );
- return res;
- }
-
- double JavaJSImpl::scopeGetNumber( jlong id , const char * field ) {
- jstring s1 = _getEnv()->NewStringUTF( field );
- double res = _getEnv()->CallStaticDoubleMethod( _dbhook , _scopeGetNumber , id , s1 );
- _getEnv()->DeleteLocalRef( s1 );
- return res;
- }
-
- jboolean JavaJSImpl::scopeGetBoolean( jlong id , const char * field ) {
- jstring s1 = _getEnv()->NewStringUTF( field );
- jboolean res = _getEnv()->CallStaticBooleanMethod( _dbhook , _scopeGetBoolean , id , s1 );
- _getEnv()->DeleteLocalRef( s1 );
- return res;
- }
-
- string JavaJSImpl::scopeGetString( jlong id , const char * field ) {
- jstring s1 = _getEnv()->NewStringUTF( field );
- jstring s = (jstring)_getEnv()->CallStaticObjectMethod( _dbhook , _scopeGetString , id , s1 );
- _getEnv()->DeleteLocalRef( s1 );
-
- if ( ! s )
- return "";
-
- const char * c = _getEnv()->GetStringUTFChars( s , 0 );
- string retStr(c);
- _getEnv()->ReleaseStringUTFChars( s , c );
- return retStr;
- }
-
- BSONObj JavaJSImpl::scopeGetObject( jlong id , const char * field ) {
- jstring s1 = _getEnv()->NewStringUTF( field );
- int guess = _getEnv()->CallStaticIntMethod( _dbhook , _scopeGuessObjectSize , id , _getEnv()->NewStringUTF( field ) );
- _getEnv()->DeleteLocalRef( s1 );
-
- if ( guess == 0 )
- return BSONObj();
-
- BSONObj::Holder* holder = (BSONObj::Holder*) malloc(guess + sizeof(unsigned));
- holder->zero()
-
- jobject bb = _getEnv()->NewDirectByteBuffer( (void*)holder->data , guess );
- jassert( bb );
-
- int len = _getEnv()->CallStaticIntMethod( _dbhook , _scopeGetObject , id , _getEnv()->NewStringUTF( field ) , bb );
- _getEnv()->DeleteLocalRef( bb );
- jassert( len > 0 && len < guess );
-
- BSONObj obj(holder);
- assert( obj.objsize() <= guess );
- return obj;
- }
-
-// other
-
- jlong JavaJSImpl::functionCreate( const char * code ) {
- jstring s = _getEnv()->NewStringUTF( code );
- jassert( s );
- jlong id = _getEnv()->CallStaticLongMethod( _dbhook , _functionCreate , s );
- _getEnv()->DeleteLocalRef( s );
- return id;
- }
-
- int JavaJSImpl::invoke( jlong scope , jlong function ) {
- return _getEnv()->CallStaticIntMethod( _dbhook , _invoke , scope , function );
- }
-
-// --- fun run method
-
- void JavaJSImpl::run( const char * js ) {
- jclass c = findClass( "ed/js/JS" );
- jassert( c );
-
- jmethodID m = _getEnv()->GetStaticMethodID( c , "eval" , "(Ljava/lang/String;)Ljava/lang/Object;" );
- jassert( m );
-
- jstring s = _getEnv()->NewStringUTF( js );
- log() << _getEnv()->CallStaticObjectMethod( c , m , s ) << endl;
- _getEnv()->DeleteLocalRef( s );
- }
-
- void JavaJSImpl::printException() {
- jthrowable exc = _getEnv()->ExceptionOccurred();
- if ( exc ) {
- _getEnv()->ExceptionDescribe();
- _getEnv()->ExceptionClear();
- }
-
- }
-
- JNIEnv * JavaJSImpl::_getEnv() {
- JNIEnv * env = _envs->get();
- if ( env )
- return env;
-
- int res = _jvm->AttachCurrentThread( (void**)&env , (void*)&_vmArgs );
- if ( res ) {
- out() << "ERROR javajs attachcurrentthread fails res:" << res << '\n';
- assert(false);
- }
-
- _envs->reset( env );
- return env;
- }
-
- Scope * JavaJSImpl::createScope() {
- return new JavaScope();
- }
-
- void ScriptEngine::setup() {
- if ( ! JavaJS ) {
- JavaJS = new JavaJSImpl();
- globalScriptEngine = JavaJS;
- }
- }
-
- void jasserted(const char *msg, const char *file, unsigned line) {
- log() << "jassert failed " << msg << " " << file << " " << line << endl;
- if ( JavaJS ) JavaJS->printException();
- throw AssertionException();
- }
-
-
- const char* findEd(const char *path) {
-
-#if defined(_WIN32)
-
- if (!path) {
- path = findEd();
- }
-
- // @TODO check validity
-
- return path;
-#else
-
- if (!path) {
- return findEd();
- }
-
- log() << "Appserver location specified : " << path << endl;
-
- if (!path) {
- log() << " invalid appserver location : " << path << " : terminating - prepare for bus error" << endl;
- return 0;
- }
-
- DIR *testDir = opendir(path);
-
- if (testDir) {
- log(1) << " found directory for appserver : " << path << endl;
- closedir(testDir);
- return path;
- }
- else {
- log() << " ERROR : not a directory for specified appserver location : " << path << " - prepare for bus error" << endl;
- return null;
- }
-#endif
- }
-
- const char * findEd() {
-
-#if defined(_WIN32)
- log() << "Appserver location will be WIN32 default : c:/l/ed/" << endl;
- return "c:/l/ed";
-#else
-
- static list<const char*> possibleEdDirs;
- if ( ! possibleEdDirs.size() ) {
- possibleEdDirs.push_back( "../../ed/ed/" ); // this one for dwight dev box
- possibleEdDirs.push_back( "../ed/" );
- possibleEdDirs.push_back( "../../ed/" );
- possibleEdDirs.push_back( "../babble/" );
- possibleEdDirs.push_back( "../../babble/" );
- }
-
- for ( list<const char*>::iterator i = possibleEdDirs.begin() ; i != possibleEdDirs.end(); i++ ) {
- const char * temp = *i;
- DIR * test = opendir( temp );
- if ( ! test )
- continue;
-
- closedir( test );
- log(1) << "found directory for appserver : " << temp << endl;
- return temp;
- }
-
- return 0;
-#endif
- };
-
- const string findJars() {
-
- static list<string> possible;
- if ( ! possible.size() ) {
- possible.push_back( "./" );
- possible.push_back( "../" );
-
- log(2) << "dbExecCommand: " << dbExecCommand << endl;
-
- string dbDir = dbExecCommand;
-#ifdef WIN32
- if ( dbDir.find( "\\" ) != string::npos ) {
- dbDir = dbDir.substr( 0 , dbDir.find_last_of( "\\" ) );
- }
- else {
- dbDir = ".";
- }
-#else
- if ( dbDir.find( "/" ) != string::npos ) {
- dbDir = dbDir.substr( 0 , dbDir.find_last_of( "/" ) );
- }
- else {
- bool found = false;
-
- if ( getenv( "PATH" ) ) {
- string s = getenv( "PATH" );
- s += ":";
- pcrecpp::StringPiece input( s );
- string dir;
- pcrecpp::RE re("(.*?):");
- while ( re.Consume( &input, &dir ) ) {
- string test = dir + "/" + dbExecCommand;
- if ( boost::filesystem::exists( test ) ) {
- while ( boost::filesystem::symbolic_link_exists( test ) ) {
- char tmp[2048];
- int len = readlink( test.c_str() , tmp , 2048 );
- tmp[len] = 0;
- log(5) << " symlink " << test << " -->> " << tmp << endl;
- test = tmp;
-
- dir = test.substr( 0 , test.rfind( "/" ) );
- }
- dbDir = dir;
- found = true;
- break;
- }
- }
- }
-
- if ( ! found )
- dbDir = ".";
- }
-#endif
-
- log(2) << "dbDir [" << dbDir << "]" << endl;
- possible.push_back( ( dbDir + "/../lib/mongo/" ));
- possible.push_back( ( dbDir + "/../lib64/mongo/" ));
- possible.push_back( ( dbDir + "/../lib32/mongo/" ));
- possible.push_back( ( dbDir + "/" ));
- possible.push_back( ( dbDir + "/lib64/mongo/" ));
- possible.push_back( ( dbDir + "/lib32/mongo/" ));
- }
-
- for ( list<string>::iterator i = possible.begin() ; i != possible.end(); i++ ) {
- const string temp = *i;
- const string jarDir = ((string)temp) + "jars/";
-
- log(5) << "possible jarDir [" << jarDir << "]" << endl;
-
- path p(jarDir );
- if ( ! boost::filesystem::exists( p) )
- continue;
-
- log(1) << "found directory for jars : " << jarDir << endl;
- return temp;
- }
-
- problem() << "ERROR : can't find directory for jars - terminating" << endl;
- exit(44);
- return 0;
-
- };
-
-
-// ---
-
- JNIEXPORT void JNICALL java_native_say(JNIEnv * env , jclass, jobject outBuffer ) {
- JNI_DEBUG( "native say called!" );
-
- Message out( env->GetDirectBufferAddress( outBuffer ) , false );
- Message in;
-
- jniCallback( out , in );
- assert( ! out.doIFreeIt() );
- curNs = 0;
- }
-
- JNIEXPORT jint JNICALL java_native_call(JNIEnv * env , jclass, jobject outBuffer , jobject inBuffer ) {
- JNI_DEBUG( "native call called!" );
-
- Message out( env->GetDirectBufferAddress( outBuffer ) , false );
- Message in;
-
- jniCallback( out , in );
- curNs = 0;
-
- JNI_DEBUG( "in.data : " << in.data );
- if ( in.data && in.data->len > 0 ) {
- JNI_DEBUG( "copying data of len :" << in.data->len );
- assert( env->GetDirectBufferCapacity( inBuffer ) >= in.data->len );
- memcpy( env->GetDirectBufferAddress( inBuffer ) , in.data , in.data->len );
-
- assert( ! out.doIFreeIt() );
- assert( in.doIFreeIt() );
- return in.data->len;
- }
-
- return 0;
- }
-
-// ----
-
- void JavaJSImpl::runTest() {
-
- const int debug = 0;
-
- JavaJSImpl& JavaJS = *mongo::JavaJS;
-
- jlong scope = JavaJS.scopeCreate();
- jassert( scope );
- if ( debug ) out() << "got scope" << endl;
-
-
- jlong func1 = JavaJS.functionCreate( "foo = 5.6; bar = \"eliot\"; abc = { foo : 517 }; " );
- jassert( ! JavaJS.invoke( scope , func1 ) );
-
-
- if ( debug ) out() << "func3 start" << endl;
- jlong func3 = JavaJS.functionCreate( "function(){ z = true; } " );
- jassert( func3 );
- jassert( ! JavaJS.invoke( scope , func3 ) );
- jassert( JavaJS.scopeGetBoolean( scope , "z" ) );
- if ( debug ) out() << "func3 done" << endl;
-
- if ( debug ) out() << "going to get object" << endl;
- BSONObj obj = JavaJS.scopeGetObject( scope , "abc" );
- if ( debug ) out() << "done getting object" << endl;
-
- if ( debug ) {
- out() << "obj : " << obj.toString() << endl;
- }
-
- {
- time_t start = time(0);
- for ( int i=0; i<5000; i++ ) {
- JavaJS.scopeSetObject( scope , "obj" , &obj );
- }
- time_t end = time(0);
-
- if ( debug )
- out() << "time : " << (unsigned) ( end - start ) << endl;
- }
-
- if ( debug ) out() << "func4 start" << endl;
- JavaJS.scopeSetObject( scope , "obj" , &obj );
- if ( debug ) out() << "\t here 1" << endl;
- jlong func4 = JavaJS.functionCreate( "tojson( obj );" );
- if ( debug ) out() << "\t here 2" << endl;
- jassert( ! JavaJS.invoke( scope , func4 ) );
- if ( debug ) out() << "func4 end" << endl;
-
- if ( debug ) out() << "func5 start" << endl;
- jassert( JavaJS.scopeSetObject( scope , "c" , &obj ) );
- jlong func5 = JavaJS.functionCreate( "assert.eq( 517 , c.foo );" );
- jassert( func5 );
- jassert( ! JavaJS.invoke( scope , func5 ) );
- if ( debug ) out() << "func5 done" << endl;
-
- if ( debug ) out() << "func6 start" << endl;
- for ( int i=0; i<100; i++ ) {
- double val = i + 5;
- JavaJS.scopeSetNumber( scope , "zzz" , val );
- jlong func6 = JavaJS.functionCreate( " xxx = zzz; " );
- jassert( ! JavaJS.invoke( scope , func6 ) );
- double n = JavaJS.scopeGetNumber( scope , "xxx" );
- jassert( val == n );
- }
- if ( debug ) out() << "func6 done" << endl;
-
- jlong func7 = JavaJS.functionCreate( "return 11;" );
- jassert( ! JavaJS.invoke( scope , func7 ) );
- assert( 11 == JavaJS.scopeGetNumber( scope , "return" ) );
-
- scope = JavaJS.scopeCreate();
- jlong func8 = JavaJS.functionCreate( "function(){ return 12; }" );
- jassert( ! JavaJS.invoke( scope , func8 ) );
- assert( 12 == JavaJS.scopeGetNumber( scope , "return" ) );
-
- }
-
-#endif
-
-} // namespace mongo
diff --git a/scripting/engine_java.h b/scripting/engine_java.h
deleted file mode 100644
index b8245ba6f22..00000000000
--- a/scripting/engine_java.h
+++ /dev/null
@@ -1,223 +0,0 @@
-// engine_java.h
-
-/* 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.
- */
-
-/* this file contains code to call into java (into the 10gen sandbox) from inside the database */
-
-#pragma once
-
-#include "../pch.h"
-
-#include <jni.h>
-#include <errno.h>
-#include <sys/types.h>
-
-#if !defined(_WIN32)
-#include <dirent.h>
-#endif
-
-#include "../db/jsobj.h"
-
-#include "engine.h"
-
-namespace mongo {
-
- void jasserted(const char *msg, const char *file, unsigned line);
-#define jassert(_Expression) if ( ! ( _Expression ) ){ jasserted(#_Expression, __FILE__, __LINE__); }
-
- const char * findEd();
- const char * findEd(const char *);
- const string findJars();
-
- class BSONObj;
-
- class JavaJSImpl : public ScriptEngine {
- public:
- JavaJSImpl(const char * = 0);
- ~JavaJSImpl();
-
- jlong scopeCreate();
- int scopeInit( jlong id , const BSONObj * obj );
- int scopeSetThis( jlong id , const BSONObj * obj );
- jboolean scopeReset( jlong id );
- void scopeFree( jlong id );
-
- double scopeGetNumber( jlong id , const char * field );
- string scopeGetString( jlong id , const char * field );
- jboolean scopeGetBoolean( jlong id , const char * field );
- BSONObj scopeGetObject( jlong id , const char * field );
- char scopeGetType( jlong id , const char * field );
-
- int scopeSetNumber( jlong id , const char * field , double val );
- int scopeSetString( jlong id , const char * field , const char * val );
- int scopeSetObject( jlong id , const char * field , const BSONObj * obj );
- int scopeSetBoolean( jlong id , const char * field , jboolean val );
-
- jlong functionCreate( const char * code );
-
- /* return values:
- public static final int NO_SCOPE = -1;
- public static final int NO_FUNCTION = -2;
- public static final int INVOKE_ERROR = -3;
- public static final int INVOKE_SUCCESS = 0;
- */
- int invoke( jlong scope , jlong function );
-
- void printException();
-
- void run( const char * js );
-
- void detach( JNIEnv * env ) {
- _jvm->DetachCurrentThread();
- }
-
- Scope * createScope();
-
- void runTest();
- private:
-
- jobject create( const char * name ) {
- jclass c = findClass( name );
- if ( ! c )
- return 0;
-
- jmethodID cons = _getEnv()->GetMethodID( c , "<init>" , "()V" );
- if ( ! cons )
- return 0;
-
- return _getEnv()->NewObject( c , cons );
- }
-
- jclass findClass( const char * name ) {
- return _getEnv()->FindClass( name );
- }
-
-
- private:
-
- JNIEnv * _getEnv();
-
- JavaVM * _jvm;
- JNIEnv * _mainEnv;
- JavaVMInitArgs * _vmArgs;
-
- boost::thread_specific_ptr<JNIEnv> * _envs;
-
- jclass _dbhook;
- jclass _dbjni;
-
- jmethodID _scopeCreate;
- jmethodID _scopeInit;
- jmethodID _scopeSetThis;
- jmethodID _scopeReset;
- jmethodID _scopeFree;
-
- jmethodID _scopeGetNumber;
- jmethodID _scopeGetString;
- jmethodID _scopeGetObject;
- jmethodID _scopeGetBoolean;
- jmethodID _scopeGuessObjectSize;
- jmethodID _scopeGetType;
-
- jmethodID _scopeSetNumber;
- jmethodID _scopeSetString;
- jmethodID _scopeSetObject;
- jmethodID _scopeSetBoolean;
-
- jmethodID _functionCreate;
-
- jmethodID _invoke;
-
- };
-
- extern JavaJSImpl *JavaJS;
-
-// a javascript "scope"
- class JavaScope : public Scope {
- public:
- JavaScope() {
- s = JavaJS->scopeCreate();
- }
- virtual ~JavaScope() {
- JavaJS->scopeFree(s);
- s = 0;
- }
- void reset() {
- JavaJS->scopeReset(s);
- }
-
- void init( BSONObj * o ) {
- JavaJS->scopeInit( s , o );
- }
-
- void localConnect( const char * dbName ) {
- setString("$client", dbName );
- }
-
- double getNumber(const char *field) {
- return JavaJS->scopeGetNumber(s,field);
- }
- string getString(const char *field) {
- return JavaJS->scopeGetString(s,field);
- }
- bool getBoolean(const char *field) {
- return JavaJS->scopeGetBoolean(s,field);
- }
- BSONObj getObject(const char *field ) {
- return JavaJS->scopeGetObject(s,field);
- }
- int type(const char *field ) {
- return JavaJS->scopeGetType(s,field);
- }
-
- void setThis( const BSONObj * obj ) {
- JavaJS->scopeSetThis( s , obj );
- }
-
- void setNumber(const char *field, double val ) {
- JavaJS->scopeSetNumber(s,field,val);
- }
- void setString(const char *field, const char * val ) {
- JavaJS->scopeSetString(s,field,val);
- }
- void setObject(const char *field, const BSONObj& obj , bool readOnly ) {
- uassert( 10211 , "only readOnly setObject supported in java" , readOnly );
- JavaJS->scopeSetObject(s,field,&obj);
- }
- void setBoolean(const char *field, bool val ) {
- JavaJS->scopeSetBoolean(s,field,val);
- }
-
- ScriptingFunction createFunction( const char * code ) {
- return JavaJS->functionCreate( code );
- }
-
- int invoke( ScriptingFunction function , const BSONObj& args ) {
- setObject( "args" , args , true );
- return JavaJS->invoke(s,function);
- }
-
- string getError() {
- return getString( "error" );
- }
-
- jlong s;
- };
-
- JNIEXPORT void JNICALL java_native_say(JNIEnv *, jclass, jobject outBuffer );
- JNIEXPORT jint JNICALL java_native_call(JNIEnv *, jclass, jobject outBuffer , jobject inBuffer );
-
-} // namespace mongo
diff --git a/scripting/engine_none.cpp b/scripting/engine_none.cpp
deleted file mode 100644
index d13dbecc06e..00000000000
--- a/scripting/engine_none.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// engine_none.cpp
-
-/* 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.
- */
-
-#include "engine.h"
-
-namespace mongo {
- void ScriptEngine::setup() {
- // noop
- }
-}
diff --git a/scripting/engine_spidermonkey.cpp b/scripting/engine_spidermonkey.cpp
deleted file mode 100644
index 64fe21cd098..00000000000
--- a/scripting/engine_spidermonkey.cpp
+++ /dev/null
@@ -1,1749 +0,0 @@
-// engine_spidermonkey.cpp
-
-/* 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.
- */
-
-#include "pch.h"
-#include "engine_spidermonkey.h"
-#include "../client/dbclient.h"
-
-#ifndef _WIN32
-#include <boost/date_time/posix_time/posix_time.hpp>
-#undef assert
-#define assert MONGO_assert
-#endif
-
-#define smuassert( cx , msg , val ) \
- if ( ! ( val ) ){ \
- JS_ReportError( cx , msg ); \
- return JS_FALSE; \
- }
-
-#define CHECKNEWOBJECT(xx,ctx,w) \
- if ( ! xx ){ \
- massert(13072,(string)"JS_NewObject failed: " + w ,xx); \
- }
-
-#define CHECKJSALLOC( newthing ) \
- massert( 13615 , "JS allocation failed, either memory leak or using too much memory" , newthing )
-
-namespace mongo {
-
- class InvalidUTF8Exception : public UserException {
- public:
- InvalidUTF8Exception() : UserException( 9006 , "invalid utf8" ) {
- }
- };
-
- string trim( string s ) {
- while ( s.size() && isspace( s[0] ) )
- s = s.substr( 1 );
-
- while ( s.size() && isspace( s[s.size()-1] ) )
- s = s.substr( 0 , s.size() - 1 );
-
- return s;
- }
-
- boost::thread_specific_ptr<SMScope> currentScope( dontDeleteScope );
- boost::recursive_mutex &smmutex = *( new boost::recursive_mutex );
-#define smlock recursive_scoped_lock ___lk( smmutex );
-
-#define GETHOLDER(x,o) ((BSONHolder*)JS_GetPrivate( x , o ))
-
- class BSONFieldIterator;
-
- class BSONHolder {
- public:
-
- BSONHolder( BSONObj obj ) {
- _obj = obj.getOwned();
- _inResolve = false;
- _modified = false;
- _magic = 17;
- }
-
- ~BSONHolder() {
- _magic = 18;
- }
-
- void check() {
- uassert( 10212 , "holder magic value is wrong" , _magic == 17 && _obj.isValid() );
- }
-
- BSONFieldIterator * it();
-
- BSONObj _obj;
- bool _inResolve;
- char _magic;
- list<string> _extra;
- set<string> _removed;
- bool _modified;
- };
-
- class BSONFieldIterator {
- public:
-
- BSONFieldIterator( BSONHolder * holder ) {
-
- set<string> added;
-
- BSONObjIterator it( holder->_obj );
- while ( it.more() ) {
- BSONElement e = it.next();
- if ( holder->_removed.count( e.fieldName() ) )
- continue;
- _names.push_back( e.fieldName() );
- added.insert( e.fieldName() );
- }
-
- for ( list<string>::iterator i = holder->_extra.begin(); i != holder->_extra.end(); i++ ) {
- if ( ! added.count( *i ) )
- _names.push_back( *i );
- }
-
- _it = _names.begin();
- }
-
- bool more() {
- return _it != _names.end();
- }
-
- string next() {
- string s = *_it;
- _it++;
- return s;
- }
-
- private:
- list<string> _names;
- list<string>::iterator _it;
- };
-
- BSONFieldIterator * BSONHolder::it() {
- return new BSONFieldIterator( this );
- }
-
- class TraverseStack {
- public:
- TraverseStack() {
- _o = 0;
- _parent = 0;
- }
-
- TraverseStack( JSObject * o , const TraverseStack * parent ) {
- _o = o;
- _parent = parent;
- }
-
- TraverseStack dive( JSObject * o ) const {
- if ( o ) {
- uassert( 13076 , (string)"recursive toObject" , ! has( o ) );
- }
- return TraverseStack( o , this );
- }
-
- int depth() const {
- int d = 0;
- const TraverseStack * s = _parent;
- while ( s ) {
- s = s->_parent;
- d++;
- }
- return d;
- }
-
- bool isTop() const {
- return _parent == 0;
- }
-
- bool has( JSObject * o ) const {
- if ( ! o )
- return false;
- const TraverseStack * s = this;
- while ( s ) {
- if ( s->_o == o )
- return true;
- s = s->_parent;
- }
- return false;
- }
-
- JSObject * _o;
- const TraverseStack * _parent;
- };
-
- class Convertor : boost::noncopyable {
- public:
- Convertor( JSContext * cx ) {
- _context = cx;
- }
-
- string toString( JSString * so ) {
- jschar * s = JS_GetStringChars( so );
- size_t srclen = JS_GetStringLength( so );
- if( srclen == 0 )
- return "";
-
- size_t len = srclen * 6; // we only need *3, but see note on len below
- char * dst = (char*)malloc( len );
-
- len /= 2;
- // doc re weird JS_EncodeCharacters api claims len expected in 16bit
- // units, but experiments suggest 8bit units expected. We allocate
- // enough memory that either will work.
-
- if ( !JS_EncodeCharacters( _context , s , srclen , dst , &len) ) {
- StringBuilder temp;
- temp << "Not proper UTF-16: ";
- for ( size_t i=0; i<srclen; i++ ) {
- if ( i > 0 )
- temp << ",";
- temp << s[i];
- }
- uasserted( 13498 , temp.str() );
- }
-
- string ss( dst , len );
- free( dst );
- if ( !JS_CStringsAreUTF8() )
- for( string::const_iterator i = ss.begin(); i != ss.end(); ++i )
- uassert( 10213 , "non ascii character detected", (unsigned char)(*i) <= 127 );
- return ss;
- }
-
- string toString( jsval v ) {
- return toString( JS_ValueToString( _context , v ) );
- }
-
- // NOTE No validation of passed in object
- long long toNumberLongUnsafe( JSObject *o ) {
- boost::uint64_t val;
- if ( hasProperty( o, "top" ) ) {
- val =
- ( (boost::uint64_t)(boost::uint32_t)getNumber( o , "top" ) << 32 ) +
- ( boost::uint32_t)( getNumber( o , "bottom" ) );
- }
- else {
- val = (boost::uint64_t)(boost::int64_t) getNumber( o, "floatApprox" );
- }
- return val;
- }
-
- int toNumberInt( JSObject *o ) {
- return (boost::uint32_t)(boost::int32_t) getNumber( o, "floatApprox" );
- }
-
- double toNumber( jsval v ) {
- double d;
- uassert( 10214 , "not a number" , JS_ValueToNumber( _context , v , &d ) );
- return d;
- }
-
- bool toBoolean( jsval v ) {
- JSBool b;
- assert( JS_ValueToBoolean( _context, v , &b ) );
- return b;
- }
-
- OID toOID( jsval v ) {
- JSContext * cx = _context;
- assert( JSVAL_IS_OID( v ) );
-
- JSObject * o = JSVAL_TO_OBJECT( v );
- OID oid;
- oid.init( getString( o , "str" ) );
- return oid;
- }
-
- BSONObj toObject( JSObject * o , const TraverseStack& stack=TraverseStack() ) {
- if ( ! o )
- return BSONObj();
-
- if ( JS_InstanceOf( _context , o , &bson_ro_class , 0 ) ) {
- BSONHolder * holder = GETHOLDER( _context , o );
- assert( holder );
- return holder->_obj.getOwned();
- }
-
- BSONObj orig;
- if ( JS_InstanceOf( _context , o , &bson_class , 0 ) ) {
- BSONHolder * holder = GETHOLDER(_context,o);
- assert( holder );
- if ( ! holder->_modified ) {
- return holder->_obj;
- }
- orig = holder->_obj;
- }
-
- BSONObjBuilder b;
-
- if ( ! appendSpecialDBObject( this , b , "value" , OBJECT_TO_JSVAL( o ) , o ) ) {
-
- if ( stack.isTop() ) {
- jsval theid = getProperty( o , "_id" );
- if ( ! JSVAL_IS_VOID( theid ) ) {
- append( b , "_id" , theid , EOO , stack.dive( o ) );
- }
- }
-
- JSIdArray * properties = JS_Enumerate( _context , o );
- assert( properties );
-
- for ( jsint i=0; i<properties->length; i++ ) {
- jsid id = properties->vector[i];
- jsval nameval;
- assert( JS_IdToValue( _context ,id , &nameval ) );
- string name = toString( nameval );
- if ( stack.isTop() && name == "_id" )
- continue;
-
- append( b , name , getProperty( o , name.c_str() ) , orig[name].type() , stack.dive( o ) );
- }
-
- JS_DestroyIdArray( _context , properties );
- }
-
- return b.obj();
- }
-
- BSONObj toObject( jsval v ) {
- if ( JSVAL_IS_NULL( v ) ||
- JSVAL_IS_VOID( v ) )
- return BSONObj();
-
- uassert( 10215 , "not an object" , JSVAL_IS_OBJECT( v ) );
- return toObject( JSVAL_TO_OBJECT( v ) );
- }
-
- string getFunctionCode( JSFunction * func ) {
- return toString( JS_DecompileFunction( _context , func , 0 ) );
- }
-
- string getFunctionCode( jsval v ) {
- uassert( 10216 , "not a function" , JS_TypeOfValue( _context , v ) == JSTYPE_FUNCTION );
- return getFunctionCode( JS_ValueToFunction( _context , v ) );
- }
-
- void appendRegex( BSONObjBuilder& b , const string& name , string s ) {
- assert( s[0] == '/' );
- s = s.substr(1);
- string::size_type end = s.rfind( '/' );
- b.appendRegex( name , s.substr( 0 , end ) , s.substr( end + 1 ) );
- }
-
- void append( BSONObjBuilder& b , string name , jsval val , BSONType oldType = EOO , const TraverseStack& stack=TraverseStack() ) {
- //cout << "name: " << name << "\t" << typeString( val ) << " oldType: " << oldType << endl;
- switch ( JS_TypeOfValue( _context , val ) ) {
-
- case JSTYPE_VOID: b.appendUndefined( name ); break;
- case JSTYPE_NULL: b.appendNull( name ); break;
-
- case JSTYPE_NUMBER: {
- double d = toNumber( val );
- if ( oldType == NumberInt && ((int)d) == d )
- b.append( name , (int)d );
- else
- b.append( name , d );
- break;
- }
- case JSTYPE_STRING: b.append( name , toString( val ) ); break;
- case JSTYPE_BOOLEAN: b.appendBool( name , toBoolean( val ) ); break;
-
- case JSTYPE_OBJECT: {
- JSObject * o = JSVAL_TO_OBJECT( val );
- if ( ! o || o == JSVAL_NULL ) {
- b.appendNull( name );
- }
- else if ( ! appendSpecialDBObject( this , b , name , val , o ) ) {
- BSONObj sub = toObject( o , stack );
- if ( JS_IsArrayObject( _context , o ) ) {
- b.appendArray( name , sub );
- }
- else {
- b.append( name , sub );
- }
- }
- break;
- }
-
- case JSTYPE_FUNCTION: {
- string s = toString(val);
- if ( s[0] == '/' ) {
- appendRegex( b , name , s );
- }
- else {
- b.appendCode( name , getFunctionCode( val ) );
- }
- break;
- }
-
- default: uassert( 10217 , (string)"can't append field. name:" + name + " type: " + typeString( val ) , 0 );
- }
- }
-
- // ---------- to spider monkey ---------
-
- bool hasFunctionIdentifier( const string& code ) {
- if ( code.size() < 9 || code.find( "function" ) != 0 )
- return false;
-
- return code[8] == ' ' || code[8] == '(';
- }
-
- bool isSimpleStatement( const string& code ) {
- if ( hasJSReturn( code ) )
- return false;
-
- if ( code.find( ';' ) != string::npos &&
- code.find( ';' ) != code.rfind( ';' ) )
- return false;
-
- if ( code.find( '\n') != string::npos )
- return false;
-
- if ( code.find( "for(" ) != string::npos ||
- code.find( "for (" ) != string::npos ||
- code.find( "while (" ) != string::npos ||
- code.find( "while(" ) != string::npos )
- return false;
-
- return true;
- }
-
- void addRoot( JSFunction * f , const char * name );
-
- JSFunction * compileFunction( const char * code, JSObject * assoc = 0 ) {
- const char * gcName = "unknown";
- JSFunction * f = _compileFunction( code , assoc , gcName );
- //addRoot( f , gcName );
- return f;
- }
-
- JSFunction * _compileFunction( const char * raw , JSObject * assoc , const char *& gcName ) {
- if ( ! assoc )
- assoc = JS_GetGlobalObject( _context );
-
- raw = jsSkipWhiteSpace( raw );
-
- //cout << "RAW\n---\n" << raw << "\n---" << endl;
-
- stringstream fname;
- fname << "cf_";
- static int fnum = 1;
- fname << "_" << fnum++ << "_";
-
-
- if ( ! hasFunctionIdentifier( raw ) ) {
- string s = raw;
- if ( isSimpleStatement( s ) ) {
- s = "return " + s;
- }
- gcName = "cf anon";
- fname << "anon";
- return JS_CompileFunction( _context , assoc , fname.str().c_str() , 0 , 0 , s.c_str() , s.size() , "nofile_a" , 0 );
- }
-
- string code = raw;
-
- size_t start = code.find( '(' );
- assert( start != string::npos );
-
- fname << "_f_" << trim( code.substr( 9 , start - 9 ) );
-
- code = code.substr( start + 1 );
- size_t end = code.find( ')' );
- assert( end != string::npos );
-
- string paramString = trim( code.substr( 0 , end ) );
- code = code.substr( end + 1 );
-
- vector<string> params;
- while ( paramString.size() ) {
- size_t c = paramString.find( ',' );
- if ( c == string::npos ) {
- params.push_back( paramString );
- break;
- }
- params.push_back( trim( paramString.substr( 0 , c ) ) );
- paramString = trim( paramString.substr( c + 1 ) );
- paramString = trim( paramString );
- }
-
- boost::scoped_array<const char *> paramArray (new const char*[params.size()]);
- for ( size_t i=0; i<params.size(); i++ )
- paramArray[i] = params[i].c_str();
-
- JSFunction * func = JS_CompileFunction( _context , assoc , fname.str().c_str() , params.size() , paramArray.get() , code.c_str() , code.size() , "nofile_b" , 0 );
-
- if ( ! func ) {
- log() << "compile failed for: " << raw << endl;
- return 0;
- }
- gcName = "cf normal";
- return func;
- }
-
- jsval toval( double d ) {
- jsval val;
- assert( JS_NewNumberValue( _context, d , &val ) );
- return val;
- }
-
- jsval toval( const char * c ) {
- JSString * s = JS_NewStringCopyZ( _context , c );
- if ( s )
- return STRING_TO_JSVAL( s );
-
- // possibly unicode, try manual
-
- size_t len = strlen( c );
- size_t dstlen = len * 4;
- jschar * dst = (jschar*)malloc( dstlen );
-
- JSBool res = JS_DecodeBytes( _context , c , len , dst, &dstlen );
- if ( res ) {
- s = JS_NewUCStringCopyN( _context , dst , dstlen );
- }
-
- free( dst );
-
- if ( ! res ) {
- tlog() << "decode failed. probably invalid utf-8 string [" << c << "]" << endl;
- jsval v;
- if ( JS_GetPendingException( _context , &v ) )
- tlog() << "\t why: " << toString( v ) << endl;
- throw InvalidUTF8Exception();
- }
-
- CHECKJSALLOC( s );
- return STRING_TO_JSVAL( s );
- }
-
- JSObject * toJSObject( const BSONObj * obj , bool readOnly=false ) {
- static string ref = "$ref";
- if ( ref == obj->firstElementFieldName() ) {
- JSObject * o = JS_NewObject( _context , &dbref_class , NULL, NULL);
- CHECKNEWOBJECT(o,_context,"toJSObject1");
- assert( JS_SetPrivate( _context , o , (void*)(new BSONHolder( obj->getOwned() ) ) ) );
- return o;
- }
- JSObject * o = JS_NewObject( _context , readOnly ? &bson_ro_class : &bson_class , NULL, NULL);
- CHECKNEWOBJECT(o,_context,"toJSObject2");
- assert( JS_SetPrivate( _context , o , (void*)(new BSONHolder( obj->getOwned() ) ) ) );
- return o;
- }
-
- jsval toval( const BSONObj* obj , bool readOnly=false ) {
- JSObject * o = toJSObject( obj , readOnly );
- return OBJECT_TO_JSVAL( o );
- }
-
- void makeLongObj( long long n, JSObject * o ) {
- boost::uint64_t val = (boost::uint64_t)n;
- CHECKNEWOBJECT(o,_context,"NumberLong1");
- double floatApprox = (double)(boost::int64_t)val;
- setProperty( o , "floatApprox" , toval( floatApprox ) );
- if ( (boost::int64_t)val != (boost::int64_t)floatApprox ) {
- // using 2 doubles here instead of a single double because certain double
- // bit patterns represent undefined values and sm might trash them
- setProperty( o , "top" , toval( (double)(boost::uint32_t)( val >> 32 ) ) );
- setProperty( o , "bottom" , toval( (double)(boost::uint32_t)( val & 0x00000000ffffffff ) ) );
- }
- }
-
- jsval toval( long long n ) {
- JSObject * o = JS_NewObject( _context , &numberlong_class , 0 , 0 );
- makeLongObj( n, o );
- return OBJECT_TO_JSVAL( o );
- }
-
- void makeIntObj( int n, JSObject * o ) {
- boost::uint32_t val = (boost::uint32_t)n;
- CHECKNEWOBJECT(o,_context,"NumberInt1");
- double floatApprox = (double)(boost::int32_t)val;
- setProperty( o , "floatApprox" , toval( floatApprox ) );
- }
-
- jsval toval( int n ) {
- JSObject * o = JS_NewObject( _context , &numberint_class , 0 , 0 );
- makeIntObj( n, o );
- return OBJECT_TO_JSVAL( o );
- }
-
- jsval toval( const BSONElement& e ) {
-
- switch( e.type() ) {
- case EOO:
- case jstNULL:
- case Undefined:
- return JSVAL_NULL;
- case NumberDouble:
- case NumberInt:
- return toval( e.number() );
-// case NumberInt:
-// return toval( e.numberInt() );
- case Symbol: // TODO: should we make a special class for this
- case String:
- return toval( e.valuestr() );
- case Bool:
- return e.boolean() ? JSVAL_TRUE : JSVAL_FALSE;
- case Object: {
- BSONObj embed = e.embeddedObject().getOwned();
- return toval( &embed );
- }
- case Array: {
-
- BSONObj embed = e.embeddedObject().getOwned();
-
- if ( embed.isEmpty() ) {
- return OBJECT_TO_JSVAL( JS_NewArrayObject( _context , 0 , 0 ) );
- }
-
- JSObject * array = JS_NewArrayObject( _context , 1 , 0 );
- CHECKJSALLOC( array );
-
- jsval myarray = OBJECT_TO_JSVAL( array );
-
- BSONObjIterator i( embed );
- while ( i.more() ){
- const BSONElement& e = i.next();
- jsval v = toval( e );
- assert( JS_SetElement( _context , array , atoi(e.fieldName()) , &v ) );
- }
-
- return myarray;
- }
- case jstOID: {
- OID oid = e.__oid();
- JSObject * o = JS_NewObject( _context , &object_id_class , 0 , 0 );
- CHECKNEWOBJECT(o,_context,"jstOID");
- setProperty( o , "str" , toval( oid.str().c_str() ) );
- return OBJECT_TO_JSVAL( o );
- }
- case RegEx: {
- const char * flags = e.regexFlags();
- uintN flagNumber = 0;
- while ( *flags ) {
- switch ( *flags ) {
- case 'g': flagNumber |= JSREG_GLOB; break;
- case 'i': flagNumber |= JSREG_FOLD; break;
- case 'm': flagNumber |= JSREG_MULTILINE; break;
- //case 'y': flagNumber |= JSREG_STICKY; break;
-
- default:
- log() << "warning: unknown regex flag:" << *flags << endl;
- }
- flags++;
- }
-
- JSObject * r = JS_NewRegExpObject( _context , (char*)e.regex() , strlen( e.regex() ) , flagNumber );
- assert( r );
- return OBJECT_TO_JSVAL( r );
- }
- case Code: {
- JSFunction * func = compileFunction( e.valuestr() );
- if ( func )
- return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) );
- return JSVAL_NULL;
- }
- case CodeWScope: {
- JSFunction * func = compileFunction( e.codeWScopeCode() );
-
- BSONObj extraScope = e.codeWScopeObject();
- if ( ! extraScope.isEmpty() ) {
- log() << "warning: CodeWScope doesn't transfer to db.eval" << endl;
- }
-
- return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) );
- }
- case Date:
- return OBJECT_TO_JSVAL( js_NewDateObjectMsec( _context , (jsdouble) ((long long)e.date().millis) ) );
-
- case MinKey:
- return OBJECT_TO_JSVAL( JS_NewObject( _context , &minkey_class , 0 , 0 ) );
-
- case MaxKey:
- return OBJECT_TO_JSVAL( JS_NewObject( _context , &maxkey_class , 0 , 0 ) );
-
- case Timestamp: {
- JSObject * o = JS_NewObject( _context , &timestamp_class , 0 , 0 );
- CHECKNEWOBJECT(o,_context,"Timestamp1");
- setProperty( o , "t" , toval( (double)(e.timestampTime()) ) );
- setProperty( o , "i" , toval( (double)(e.timestampInc()) ) );
- return OBJECT_TO_JSVAL( o );
- }
- case NumberLong: {
- return toval( e.numberLong() );
- }
- case DBRef: {
- JSObject * o = JS_NewObject( _context , &dbpointer_class , 0 , 0 );
- CHECKNEWOBJECT(o,_context,"DBRef1");
- setProperty( o , "ns" , toval( e.dbrefNS() ) );
-
- JSObject * oid = JS_NewObject( _context , &object_id_class , 0 , 0 );
- CHECKNEWOBJECT(oid,_context,"DBRef2");
- setProperty( oid , "str" , toval( e.dbrefOID().str().c_str() ) );
-
- setProperty( o , "id" , OBJECT_TO_JSVAL( oid ) );
- return OBJECT_TO_JSVAL( o );
- }
- case BinData: {
- JSObject * o = JS_NewObject( _context , &bindata_class , 0 , 0 );
- CHECKNEWOBJECT(o,_context,"Bindata_BinData1");
- int len;
- const char * data = e.binData( len );
- assert( data );
- assert( JS_SetPrivate( _context , o , new BinDataHolder( data , len ) ) );
-
- setProperty( o , "len" , toval( (double)len ) );
- setProperty( o , "type" , toval( (double)e.binDataType() ) );
- return OBJECT_TO_JSVAL( o );
- }
- }
-
- log() << "toval: unknown type: " << (int) e.type() << endl;
- uassert( 10218 , "not done: toval" , 0 );
- return 0;
- }
-
- // ------- object helpers ------
-
- JSObject * getJSObject( JSObject * o , const char * name ) {
- jsval 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 ) {
- uassert( 10219 , "object passed to getPropery is null" , o );
- 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 ) );
- }
-
- string typeString( jsval v ) {
- JSType t = JS_TypeOfValue( _context , v );
- return JS_GetTypeName( _context , t );
- }
-
- bool getBoolean( JSObject * o , const char * field ) {
- return toBoolean( getProperty( o , field ) );
- }
-
- double getNumber( JSObject * o , const char * field ) {
- return toNumber( getProperty( o , field ) );
- }
-
- string getString( JSObject * o , const char * field ) {
- return toString( getProperty( o , field ) );
- }
-
- JSClass * getClass( JSObject * o , const char * field ) {
- jsval v;
- assert( JS_GetProperty( _context , o , field , &v ) );
- if ( ! JSVAL_IS_OBJECT( v ) )
- return 0;
- return JS_GET_CLASS( _context , JSVAL_TO_OBJECT( v ) );
- }
-
- JSContext * _context;
-
-
- };
-
-
- void bson_finalize( JSContext * cx , JSObject * obj ) {
- BSONHolder * o = GETHOLDER( cx , obj );
- if ( o ) {
- delete o;
- assert( JS_SetPrivate( cx , obj , 0 ) );
- }
- }
-
- JSBool bson_enumerate( JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp ) {
-
- BSONHolder * o = GETHOLDER( cx , obj );
-
- if ( enum_op == JSENUMERATE_INIT ) {
- if ( o ) {
- BSONFieldIterator * it = o->it();
- *statep = PRIVATE_TO_JSVAL( it );
- }
- else {
- *statep = 0;
- }
- if ( idp )
- *idp = JSVAL_ZERO;
- return JS_TRUE;
- }
-
- BSONFieldIterator * it = (BSONFieldIterator*)JSVAL_TO_PRIVATE( *statep );
- if ( ! it ) {
- *statep = 0;
- return JS_TRUE;
- }
-
- if ( enum_op == JSENUMERATE_NEXT ) {
- if ( it->more() ) {
- string name = it->next();
- Convertor c(cx);
- assert( JS_ValueToId( cx , c.toval( name.c_str() ) , idp ) );
- }
- else {
- delete it;
- *statep = 0;
- }
- return JS_TRUE;
- }
-
- if ( enum_op == JSENUMERATE_DESTROY ) {
- if ( it )
- delete it;
- return JS_TRUE;
- }
-
- uassert( 10220 , "don't know what to do with this op" , 0 );
- return JS_FALSE;
- }
-
- JSBool noaccess( JSContext *cx, JSObject *obj, jsval idval, jsval *vp) {
- BSONHolder * holder = GETHOLDER( cx , obj );
- if ( ! holder ) {
- // in init code still
- return JS_TRUE;
- }
- if ( holder->_inResolve )
- return JS_TRUE;
- JS_ReportError( cx , "doing write op on read only operation" );
- return JS_FALSE;
- }
-
- JSClass bson_ro_class = {
- "bson_ro_object" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE ,
- noaccess, noaccess, JS_PropertyStub, noaccess,
- (JSEnumerateOp)bson_enumerate, (JSResolveOp)(&resolveBSONField) , JS_ConvertStub, bson_finalize ,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSBool bson_cons( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- cerr << "bson_cons : shouldn't be here!" << endl;
- JS_ReportError( cx , "can't construct bson object" );
- return JS_FALSE;
- }
-
- JSFunctionSpec bson_functions[] = {
- { 0 }
- };
-
- JSBool bson_add_prop( JSContext *cx, JSObject *obj, jsval idval, jsval *vp) {
- BSONHolder * holder = GETHOLDER( cx , obj );
- if ( ! holder ) {
- // static init
- return JS_TRUE;
- }
- if ( ! holder->_inResolve ) {
- Convertor c(cx);
- string name = c.toString( idval );
- if ( holder->_obj[name].eoo() ) {
- holder->_extra.push_back( name );
- }
- holder->_modified = true;
- }
- return JS_TRUE;
- }
-
-
- JSBool mark_modified( JSContext *cx, JSObject *obj, jsval idval, jsval *vp) {
- Convertor c(cx);
- BSONHolder * holder = GETHOLDER( cx , obj );
- if ( !holder ) // needed when we're messing with DBRef.prototype
- return JS_TRUE;
- if ( holder->_inResolve )
- return JS_TRUE;
- holder->_modified = true;
- holder->_removed.erase( c.toString( idval ) );
- return JS_TRUE;
- }
-
- JSBool mark_modified_remove( JSContext *cx, JSObject *obj, jsval idval, jsval *vp) {
- Convertor c(cx);
- BSONHolder * holder = GETHOLDER( cx , obj );
- if ( holder->_inResolve )
- return JS_TRUE;
- holder->_modified = true;
- holder->_removed.insert( c.toString( idval ) );
- return JS_TRUE;
- }
-
- JSClass bson_class = {
- "bson_object" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE ,
- bson_add_prop, mark_modified_remove, JS_PropertyStub, mark_modified,
- (JSEnumerateOp)bson_enumerate, (JSResolveOp)(&resolveBSONField) , JS_ConvertStub, bson_finalize ,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- static JSClass global_class = {
- "global", JSCLASS_GLOBAL_FLAGS,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- // --- global helpers ---
-
- JSBool hexToBinData(JSContext * cx, jsval *rval, int subtype, string s) {
- JSObject * o = JS_NewObject( cx , &bindata_class , 0 , 0 );
- CHECKNEWOBJECT(o,_context,"Bindata_BinData1");
- int len = s.size() / 2;
- char * data = new char[len];
- char *p = data;
- const char *src = s.c_str();
- for( size_t i = 0; i+1 < s.size(); i += 2 ) {
- *p++ = fromHex(src + i);
- }
- assert( JS_SetPrivate( cx , o , new BinDataHolder( data , len ) ) );
- Convertor c(cx);
- c.setProperty( o, "len", c.toval((double)len) );
- c.setProperty( o, "type", c.toval((double)subtype) );
- *rval = OBJECT_TO_JSVAL( o );
- delete data;
- return JS_TRUE;
- }
-
- JSBool _HexData( JSContext * cx , JSObject * obj , uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
- if ( argc != 2 ) {
- JS_ReportError( cx , "HexData needs 2 arguments -- HexData(subtype,hexstring)" );
- return JS_FALSE;
- }
- int type = (int)c.toNumber( argv[ 0 ] );
- if ( type == 2 ) {
- JS_ReportError( cx , "BinData subtype 2 is deprecated" );
- return JS_FALSE;
- }
- string s = c.toString(argv[1]);
- return hexToBinData(cx, rval, type, s);
- }
-
- JSBool _UUID( JSContext * cx , JSObject * obj , uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
- if ( argc != 1 ) {
- JS_ReportError( cx , "UUID needs argument -- UUID(hexstring)" );
- return JS_FALSE;
- }
- string s = c.toString(argv[0]);
- if( s.size() != 32 ) {
- JS_ReportError( cx , "bad UUID hex string len" );
- return JS_FALSE;
- }
- return hexToBinData(cx, rval, 3, s);
- }
-
- JSBool _MD5( JSContext * cx , JSObject * obj , uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
- if ( argc != 1 ) {
- JS_ReportError( cx , "MD5 needs argument -- MD5(hexstring)" );
- return JS_FALSE;
- }
- string s = c.toString(argv[0]);
- if( s.size() != 32 ) {
- JS_ReportError( cx , "bad MD5 hex string len" );
- return JS_FALSE;
- }
- return hexToBinData(cx, rval, 5, s);
- }
-
- JSBool native_print( JSContext * cx , JSObject * obj , uintN argc, jsval *argv, jsval *rval ) {
- stringstream ss;
- Convertor c( cx );
- for ( uintN i=0; i<argc; i++ ) {
- if ( i > 0 )
- ss << " ";
- ss << c.toString( argv[i] );
- }
- ss << "\n";
- Logstream::logLockless( ss.str() );
- 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_gc( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ) {
- JS_GC( cx );
- return JS_TRUE;
- }
-
- JSFunctionSpec globalHelpers[] = {
- { "print" , &native_print , 0 , 0 , 0 } ,
- { "nativeHelper" , &native_helper , 1 , 0 , 0 } ,
- { "load" , &native_load , 1 , 0 , 0 } ,
- { "gc" , &native_gc , 1 , 0 , 0 } ,
- { "UUID", &_UUID, 0, 0, 0 } ,
- { "MD5", &_MD5, 0, 0, 0 } ,
- { "HexData", &_HexData, 0, 0, 0 } ,
- { 0 , 0 , 0 , 0 , 0 }
- };
-
- // ----END global helpers ----
-
- // Object helpers
-
- JSBool bson_get_size(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- if ( argc != 1 || !JSVAL_IS_OBJECT( argv[ 0 ] ) ) {
- JS_ReportError( cx , "bsonsize requires one valid object" );
- return JS_FALSE;
- }
-
- Convertor c(cx);
-
- if ( argv[0] == JSVAL_VOID || argv[0] == JSVAL_NULL ) {
- *rval = c.toval( 0.0 );
- return JS_TRUE;
- }
-
- JSObject * o = JSVAL_TO_OBJECT( argv[0] );
-
- double size = 0;
-
- if ( JS_InstanceOf( cx , o , &bson_ro_class , 0 ) ||
- JS_InstanceOf( cx , o , &bson_class , 0 ) ) {
- BSONHolder * h = GETHOLDER( cx , o );
- if ( h ) {
- size = h->_obj.objsize();
- }
- }
- else {
- BSONObj temp = c.toObject( o );
- size = temp.objsize();
- }
-
- *rval = c.toval( size );
- return JS_TRUE;
- }
-
- JSFunctionSpec objectHelpers[] = {
- { "bsonsize" , &bson_get_size , 1 , 0 , 0 } ,
- { 0 , 0 , 0 , 0 , 0 }
- };
-
- // end Object helpers
-
- JSBool resolveBSONField( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp ) {
- assert( JS_EnterLocalRootScope( cx ) );
- Convertor c( cx );
-
- BSONHolder * holder = GETHOLDER( cx , obj );
- if ( ! holder ) {
- // static init
- *objp = 0;
- JS_LeaveLocalRootScope( cx );
- return JS_TRUE;
- }
- holder->check();
-
- string s = c.toString( id );
-
- BSONElement e = holder->_obj[ s.c_str() ];
-
- if ( e.type() == EOO || holder->_removed.count( s ) ) {
- *objp = 0;
- JS_LeaveLocalRootScope( cx );
- return JS_TRUE;
- }
-
- jsval val;
- try {
- val = c.toval( e );
- }
- catch ( InvalidUTF8Exception& ) {
- JS_LeaveLocalRootScope( cx );
- JS_ReportError( cx , "invalid utf8" );
- return JS_FALSE;
- }
-
- assert( ! holder->_inResolve );
- holder->_inResolve = true;
- assert( JS_SetProperty( cx , obj , s.c_str() , &val ) );
- holder->_inResolve = false;
-
- if ( val != JSVAL_NULL && val != JSVAL_VOID && JSVAL_IS_OBJECT( val ) ) {
- // TODO: this is a hack to get around sub objects being modified
- // basically right now whenever a sub object is read we mark whole obj as possibly modified
- JSObject * oo = JSVAL_TO_OBJECT( val );
- if ( JS_InstanceOf( cx , oo , &bson_class , 0 ) ||
- JS_IsArrayObject( cx , oo ) ) {
- holder->_modified = true;
- }
- }
-
- *objp = obj;
- JS_LeaveLocalRootScope( cx );
- return JS_TRUE;
- }
-
-
- class SMScope;
-
- class SMEngine : public ScriptEngine {
- public:
-
- SMEngine() {
-#ifdef SM18
- JS_SetCStringsAreUTF8();
-#endif
-
- _runtime = JS_NewRuntime(64L * 1024L * 1024L);
- uassert( 10221 , "JS_NewRuntime failed" , _runtime );
-
- if ( ! utf8Ok() ) {
- log() << "*** warning: spider monkey build without utf8 support. consider rebuilding with utf8 support" << endl;
- }
-
- int x = 0;
- assert( x = 1 );
- uassert( 10222 , "assert not being executed" , x == 1 );
- }
-
- ~SMEngine() {
- JS_DestroyRuntime( _runtime );
- JS_ShutDown();
- }
-
- Scope * createScope();
-
- void runTest();
-
- virtual bool utf8Ok() const { return JS_CStringsAreUTF8(); }
-
-#ifdef XULRUNNER
- JSClass * _dateClass;
- JSClass * _regexClass;
-#endif
-
-
- private:
- JSRuntime * _runtime;
- friend class SMScope;
- };
-
- SMEngine * globalSMEngine;
-
-
- void ScriptEngine::setup() {
- globalSMEngine = new SMEngine();
- globalScriptEngine = globalSMEngine;
- }
-
-
- // ------ scope ------
-
-
- JSBool no_gc(JSContext *cx, JSGCStatus status) {
- return JS_FALSE;
- }
-
- JSBool yes_gc(JSContext *cx, JSGCStatus status) {
- return JS_TRUE;
- }
-
- class SMScope : public Scope {
- public:
- SMScope() : _this( 0 ) , _externalSetup( false ) , _localConnect( false ) {
- smlock;
- _context = JS_NewContext( globalSMEngine->_runtime , 8192 );
- _convertor = new Convertor( _context );
- massert( 10431 , "JS_NewContext failed" , _context );
-
- JS_SetOptions( _context , JSOPTION_VAROBJFIX);
- //JS_SetVersion( _context , JSVERSION_LATEST); TODO
- JS_SetErrorReporter( _context , errorReporter );
-
- _global = JS_NewObject( _context , &global_class, NULL, NULL);
- massert( 10432 , "JS_NewObject failed for global" , _global );
- JS_SetGlobalObject( _context , _global );
- massert( 10433 , "js init failed" , JS_InitStandardClasses( _context , _global ) );
-
- JS_SetOptions( _context , JS_GetOptions( _context ) | JSOPTION_VAROBJFIX );
-
- JS_DefineFunctions( _context , _global , globalHelpers );
-
- JS_DefineFunctions( _context , _convertor->getGlobalObject( "Object" ), objectHelpers );
-
- //JS_SetGCCallback( _context , no_gc ); // this is useful for seeing if something is a gc problem
-
- _postCreateHacks();
- }
-
- ~SMScope() {
- smlock;
- uassert( 10223 , "deleted SMScope twice?" , _convertor );
-
- for ( list<void*>::iterator i=_roots.begin(); i != _roots.end(); i++ ) {
- JS_RemoveRoot( _context , *i );
- }
- _roots.clear();
-
- if ( _this ) {
- JS_RemoveRoot( _context , &_this );
- _this = 0;
- }
-
- if ( _convertor ) {
- delete _convertor;
- _convertor = 0;
- }
-
- if ( _context ) {
- // This is expected to reclaim _global as well.
- JS_DestroyContext( _context );
- _context = 0;
- }
-
- }
-
- void reset() {
- smlock;
- assert( _convertor );
- return;
- if ( _this ) {
- JS_RemoveRoot( _context , &_this );
- _this = 0;
- }
- currentScope.reset( this );
- _error = "";
- }
-
- void addRoot( void * root , const char * name ) {
- JS_AddNamedRoot( _context , root , name );
- _roots.push_back( root );
- }
-
- void init( const BSONObj * data ) {
- smlock;
- if ( ! data )
- return;
-
- BSONObjIterator i( *data );
- while ( i.more() ) {
- BSONElement e = i.next();
- _convertor->setProperty( _global , e.fieldName() , _convertor->toval( e ) );
- _initFieldNames.insert( e.fieldName() );
- }
-
- }
-
- void externalSetup() {
- smlock;
- uassert( 10224 , "already local connected" , ! _localConnect );
- if ( _externalSetup )
- return;
- initMongoJS( this , _context , _global , false );
- _externalSetup = true;
- }
-
- void localConnect( const char * dbName ) {
- {
- smlock;
- uassert( 10225 , "already setup for external db" , ! _externalSetup );
- if ( _localConnect ) {
- uassert( 10226 , "connected to different db" , _localDBName == dbName );
- return;
- }
-
- initMongoJS( this , _context , _global , true );
-
- exec( "_mongo = new Mongo();" );
- exec( ((string)"db = _mongo.getDB( \"" + dbName + "\" ); ").c_str() );
-
- _localConnect = true;
- _localDBName = dbName;
- }
- loadStored();
- }
-
- // ----- getters ------
- double getNumber( const char *field ) {
- smlock;
- jsval val;
- assert( JS_GetProperty( _context , _global , field , &val ) );
- return _convertor->toNumber( val );
- }
-
- string getString( const char *field ) {
- smlock;
- jsval val;
- assert( JS_GetProperty( _context , _global , field , &val ) );
- JSString * s = JS_ValueToString( _context , val );
- return _convertor->toString( s );
- }
-
- bool getBoolean( const char *field ) {
- smlock;
- return _convertor->getBoolean( _global , field );
- }
-
- BSONObj getObject( const char *field ) {
- smlock;
- return _convertor->toObject( _convertor->getProperty( _global , field ) );
- }
-
- JSObject * getJSObject( const char * field ) {
- smlock;
- return _convertor->getJSObject( _global , field );
- }
-
- int type( const char *field ) {
- smlock;
- jsval val;
- assert( JS_GetProperty( _context , _global , field , &val ) );
-
- switch ( JS_TypeOfValue( _context , val ) ) {
- case JSTYPE_VOID: return Undefined;
- case JSTYPE_NULL: return jstNULL;
- case JSTYPE_OBJECT: {
- if ( val == JSVAL_NULL )
- return jstNULL;
- JSObject * o = JSVAL_TO_OBJECT( val );
- if ( JS_IsArrayObject( _context , o ) )
- return Array;
- if ( isDate( _context , o ) )
- return Date;
- return Object;
- }
- case JSTYPE_FUNCTION: return Code;
- case JSTYPE_STRING: return String;
- case JSTYPE_NUMBER: return NumberDouble;
- case JSTYPE_BOOLEAN: return Bool;
- default:
- uassert( 10227 , "unknown type" , 0 );
- }
- return 0;
- }
-
- // ----- setters ------
-
- void setElement( const char *field , const BSONElement& val ) {
- smlock;
- jsval v = _convertor->toval( val );
- assert( JS_SetProperty( _context , _global , field , &v ) );
- }
-
- void setNumber( const char *field , double val ) {
- smlock;
- jsval v = _convertor->toval( val );
- assert( JS_SetProperty( _context , _global , field , &v ) );
- }
-
- void setString( const char *field , const char * val ) {
- smlock;
- jsval v = _convertor->toval( val );
- assert( JS_SetProperty( _context , _global , field , &v ) );
- }
-
- void setObject( const char *field , const BSONObj& obj , bool readOnly ) {
- smlock;
- jsval v = _convertor->toval( &obj , readOnly );
- JS_SetProperty( _context , _global , field , &v );
- }
-
- void setBoolean( const char *field , bool val ) {
- smlock;
- jsval v = BOOLEAN_TO_JSVAL( val );
- assert( JS_SetProperty( _context , _global , field , &v ) );
- }
-
- void setThis( const BSONObj * obj ) {
- smlock;
- if ( _this ) {
- JS_RemoveRoot( _context , &_this );
- _this = 0;
- }
-
- if ( obj ) {
- _this = _convertor->toJSObject( obj );
- JS_AddNamedRoot( _context , &_this , "scope this" );
- }
- }
-
- void setFunction( const char *field , const char * code ) {
- smlock;
- jsval v = OBJECT_TO_JSVAL(JS_GetFunctionObject(_convertor->compileFunction(code)));
- JS_SetProperty( _context , _global , field , &v );
- }
-
- void rename( const char * from , const char * to ) {
- smlock;
- jsval v;
- assert( JS_GetProperty( _context , _global , from , &v ) );
- assert( JS_SetProperty( _context , _global , to , &v ) );
- v = JSVAL_VOID;
- assert( JS_SetProperty( _context , _global , from , &v ) );
- }
-
- // ---- functions -----
-
- ScriptingFunction _createFunction( const char * code ) {
- smlock;
- precall();
- return (ScriptingFunction)_convertor->compileFunction( code );
- }
-
- struct TimeoutSpec {
- boost::posix_time::ptime start;
- boost::posix_time::time_duration timeout;
- int count;
- };
-
- // should not generate exceptions, as those can be caught in
- // javascript code; returning false without an exception exits
- // immediately
- static JSBool _interrupt( JSContext *cx ) {
- TimeoutSpec &spec = *(TimeoutSpec *)( JS_GetContextPrivate( cx ) );
- if ( ++spec.count % 1000 != 0 )
- return JS_TRUE;
- const char * interrupt = ScriptEngine::checkInterrupt();
- if ( interrupt && interrupt[ 0 ] ) {
- return JS_FALSE;
- }
- if ( spec.timeout.ticks() == 0 ) {
- return JS_TRUE;
- }
- boost::posix_time::time_duration elapsed = ( boost::posix_time::microsec_clock::local_time() - spec.start );
- if ( elapsed < spec.timeout ) {
- return JS_TRUE;
- }
- return JS_FALSE;
-
- }
-
- static JSBool interrupt( JSContext *cx, JSScript *script ) {
- return _interrupt( cx );
- }
-
- void installInterrupt( int timeoutMs ) {
- if ( timeoutMs != 0 || ScriptEngine::haveCheckInterruptCallback() ) {
- TimeoutSpec *spec = new TimeoutSpec;
- spec->timeout = boost::posix_time::millisec( timeoutMs );
- spec->start = boost::posix_time::microsec_clock::local_time();
- spec->count = 0;
- JS_SetContextPrivate( _context, (void*)spec );
-#if defined(SM181) && !defined(XULRUNNER190)
- JS_SetOperationCallback( _context, _interrupt );
-#else
- JS_SetBranchCallback( _context, interrupt );
-#endif
- }
- }
-
- void uninstallInterrupt( int timeoutMs ) {
- if ( timeoutMs != 0 || ScriptEngine::haveCheckInterruptCallback() ) {
-#if defined(SM181) && !defined(XULRUNNER190)
- JS_SetOperationCallback( _context , 0 );
-#else
- JS_SetBranchCallback( _context, 0 );
-#endif
- delete (TimeoutSpec *)JS_GetContextPrivate( _context );
- JS_SetContextPrivate( _context, 0 );
- }
- }
-
- void precall() {
- _error = "";
- currentScope.reset( this );
- }
-
- bool exec( const StringData& code , const string& name = "(anon)" , bool printResult = false , bool reportError = true , bool assertOnError = true, int timeoutMs = 0 ) {
- smlock;
- precall();
-
- jsval ret = JSVAL_VOID;
-
- installInterrupt( timeoutMs );
- JSBool worked = JS_EvaluateScript( _context , _global , code.data() , code.size() , name.c_str() , 1 , &ret );
- uninstallInterrupt( timeoutMs );
-
- if ( ! worked && _error.size() == 0 ) {
- jsval v;
- if ( JS_GetPendingException( _context , &v ) ) {
- _error = _convertor->toString( v );
- if ( reportError )
- cout << _error << endl;
- }
- }
-
- uassert( 10228 , str::stream() << name + " exec failed: " << _error , worked || ! assertOnError );
-
- if ( reportError && ! _error.empty() ) {
- // cout << "exec error: " << _error << endl;
- // already printed in reportError, so... TODO
- }
-
- if ( worked )
- _convertor->setProperty( _global , "__lastres__" , ret );
-
- if ( worked && printResult && ! JSVAL_IS_VOID( ret ) )
- cout << _convertor->toString( ret ) << endl;
-
- return worked;
- }
-
- int invoke( JSFunction * func , const BSONObj* args, const BSONObj* recv, int timeoutMs , bool ignoreReturn, bool readOnlyArgs, bool readOnlyRecv ) {
- smlock;
- precall();
-
- assert( JS_EnterLocalRootScope( _context ) );
-
- int nargs = args ? args->nFields() : 0;
- scoped_array<jsval> smargsPtr( new jsval[nargs] );
- if ( nargs ) {
- BSONObjIterator it( *args );
- for ( int i=0; i<nargs; i++ ) {
- smargsPtr[i] = _convertor->toval( it.next() );
- }
- }
-
- if ( !args ) {
- _convertor->setProperty( _global , "args" , JSVAL_NULL );
- }
- else {
- 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 ) {
- return -3;
- }
-
- if ( ! ignoreReturn ) {
- assert( JS_SetProperty( _context , _global , "return" , &rval ) );
- }
-
- return 0;
- }
-
- int invoke( ScriptingFunction funcAddr , const BSONObj* args, const BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = 0, bool readOnlyArgs = false, bool readOnlyRecv = false ) {
- return invoke( (JSFunction*)funcAddr , args , recv, timeoutMs , ignoreReturn, readOnlyArgs, readOnlyRecv);
- }
-
- void gotError( string s ) {
- _error = s;
- }
-
- string getError() {
- return _error;
- }
-
- 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 ) );
-
- stringstream code;
- if (data) {
- _convertor->setProperty( _global , (name + "_data_").c_str() , _convertor->toval( (double)(long long)data ) );
- code << field << "_" << " = { x : " << field << "_ , y: " << field << "_data_ }; ";
- } else {
- code << field << "_" << " = { x : " << field << "_ }; ";
- }
- code << field << " = function(){ return nativeHelper.apply( " << field << "_ , arguments ); }";
- exec( code.str() );
- }
-
- virtual void gc() {
- smlock;
- JS_GC( _context );
- }
-
- JSContext *SavedContext() const { return _context; }
-
- private:
-
- void _postCreateHacks() {
-#ifdef XULRUNNER
- exec( "__x__ = new Date(1);" );
- globalSMEngine->_dateClass = _convertor->getClass( _global , "__x__" );
- exec( "__x__ = /abc/i" );
- globalSMEngine->_regexClass = _convertor->getClass( _global , "__x__" );
-#endif
- }
-
- JSContext * _context;
- Convertor * _convertor;
-
- JSObject * _global;
- JSObject * _this;
-
- string _error;
- list<void*> _roots;
-
- bool _externalSetup;
- bool _localConnect;
-
- set<string> _initFieldNames;
-
- };
-
- /* used to make the logging not overly chatty in the mongo shell. */
- extern bool isShell;
-
- void errorReporter( JSContext *cx, const char *message, JSErrorReport *report ) {
- stringstream ss;
- if( !isShell )
- ss << "JS Error: ";
- ss << message;
-
- if ( report && report->filename ) {
- ss << " " << report->filename << ":" << report->lineno;
- }
-
- tlog() << ss.str() << endl;
-
- if ( currentScope.get() ) {
- currentScope->gotError( ss.str() );
- }
- }
-
- JSBool native_load( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ) {
- Convertor c(cx);
-
- Scope * s = currentScope.get();
-
- for ( uintN i=0; i<argc; i++ ) {
- string filename = c.toString( argv[i] );
- //cout << "load [" << filename << "]" << endl;
-
- if ( ! s->execFile( filename , false , true , false ) ) {
- JS_ReportError( cx , ((string)"error loading js file: " + filename ).c_str() );
- return JS_FALSE;
- }
- }
-
- return JS_TRUE;
- }
-
-
-
- void SMEngine::runTest() {
- SMScope s;
-
- s.localConnect( "foo" );
-
- s.exec( "assert( db.getMongo() )" );
- s.exec( "assert( db.bar , 'collection getting does not work' ); " );
- s.exec( "assert.eq( db._name , 'foo' );" );
- s.exec( "assert( _mongo == db.getMongo() ); " );
- s.exec( "assert( _mongo == db._mongo ); " );
- s.exec( "assert( typeof DB.bar == 'undefined' ); " );
- s.exec( "assert( typeof DB.prototype.bar == 'undefined' , 'resolution is happening on prototype, not object' ); " );
-
- s.exec( "assert( db.bar ); " );
- s.exec( "assert( typeof db.addUser == 'function' )" );
- s.exec( "assert( db.addUser == DB.prototype.addUser )" );
- s.exec( "assert.eq( 'foo.bar' , db.bar._fullName ); " );
- s.exec( "db.bar.verify();" );
-
- s.exec( "db.bar.silly.verify();" );
- s.exec( "assert.eq( 'foo.bar.silly' , db.bar.silly._fullName )" );
- s.exec( "assert.eq( 'function' , typeof _mongo.find , 'mongo.find is not a function' )" );
-
- assert( (string)"abc" == trim( "abc" ) );
- assert( (string)"abc" == trim( " abc" ) );
- assert( (string)"abc" == trim( "abc " ) );
- assert( (string)"abc" == trim( " abc " ) );
-
- }
-
- Scope * SMEngine::createScope() {
- return new SMScope();
- }
-
- void Convertor::addRoot( JSFunction * f , const char * name ) {
- if ( ! f )
- return;
-
- SMScope * scope = currentScope.get();
- uassert( 10229 , "need a scope" , scope );
-
- JSObject * o = JS_GetFunctionObject( f );
- assert( o );
- scope->addRoot( &o , name );
- }
-
-}
-
-#include "sm_db.cpp"
diff --git a/scripting/engine_spidermonkey.h b/scripting/engine_spidermonkey.h
deleted file mode 100644
index 9fd430d853d..00000000000
--- a/scripting/engine_spidermonkey.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// engine_spidermonkey.h
-
-/* 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.
- */
-
-#pragma once
-
-#include "engine.h"
-
-// START inc hacking
-
-#ifdef WIN32
-#include "jstypes.h"
-#undef JS_PUBLIC_API
-#undef JS_PUBLIC_DATA
-#define JS_PUBLIC_API(t) t __cdecl
-#define JS_PUBLIC_DATA(t) t
-#endif
-
-#include "jsapi.h"
-#include "jsobj.h"
-#include "jsdate.h"
-#include "jsregexp.h"
-
-// END inc hacking
-
-// -- SM 1.6 hacks ---
-#ifndef JSCLASS_GLOBAL_FLAGS
-#error old version of spider monkey ( probably 1.6 ) you should upgrade to at least 1.7
-#endif
-// -- END SM 1.6 hacks ---
-
-#ifdef JSVAL_IS_TRACEABLE
-#define SM18
-#endif
-
-#ifdef XULRUNNER
-#define SM181
-#endif
-
-namespace mongo {
-
- class SMScope;
- class Convertor;
-
- extern JSClass bson_class;
- extern JSClass bson_ro_class;
-
- extern JSClass object_id_class;
- extern JSClass dbpointer_class;
- extern JSClass dbref_class;
- extern JSClass bindata_class;
- extern JSClass timestamp_class;
- extern JSClass numberlong_class;
- extern JSClass numberint_class;
- extern JSClass minkey_class;
- extern JSClass maxkey_class;
-
- // internal things
- void dontDeleteScope( SMScope * s ) {}
- void errorReporter( JSContext *cx, const char *message, JSErrorReport *report );
- extern boost::thread_specific_ptr<SMScope> currentScope;
-
- // bson
- JSBool resolveBSONField( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp );
-
-
- // mongo
- void initMongoJS( SMScope * scope , JSContext * cx , JSObject * global , bool local );
- bool appendSpecialDBObject( Convertor * c , BSONObjBuilder& b , const string& name , jsval val , JSObject * o );
-
-#define JSVAL_IS_OID(v) ( JSVAL_IS_OBJECT( v ) && JS_InstanceOf( cx , JSVAL_TO_OBJECT( v ) , &object_id_class , 0 ) )
-
- bool isDate( JSContext * cx , JSObject * o );
-
- // JS private data must be 2byte aligned, so we use a holder to refer to an unaligned pointer.
- struct BinDataHolder {
- BinDataHolder( const char *c, int copyLen = -1 ) :
- c_( const_cast< char * >( c ) ),
- iFree_( copyLen != -1 ) {
- if ( copyLen != -1 ) {
- c_ = (char*)malloc( copyLen );
- memcpy( c_, c, copyLen );
- }
- }
- ~BinDataHolder() {
- if ( iFree_ )
- free( c_ );
- }
- char *c_;
- bool iFree_;
- };
-}
diff --git a/scripting/engine_v8.cpp b/scripting/engine_v8.cpp
deleted file mode 100644
index 2173391893e..00000000000
--- a/scripting/engine_v8.cpp
+++ /dev/null
@@ -1,1547 +0,0 @@
-//engine_v8.cpp
-
-/* 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.
- */
-
-#if defined(_WIN32)
-/** this is a hack - v8stdint.h defined uint16_t etc. on _WIN32 only, and that collides with
- our usage of boost */
-#include "boost/cstdint.hpp"
-using namespace boost;
-#define V8STDINT_H_
-#endif
-
-#include "engine_v8.h"
-
-#include "v8_wrapper.h"
-#include "v8_utils.h"
-#include "v8_db.h"
-
-#define V8_SIMPLE_HEADER V8Lock l; HandleScope handle_scope; Context::Scope context_scope( _context );
-
-namespace mongo {
-
- // guarded by v8 mutex
- map< unsigned, int > __interruptSpecToThreadId;
-
- /**
- * Unwraps a BSONObj from the JS wrapper
- */
- static BSONObj* unwrapBSONObj(const Handle<v8::Object>& obj) {
- Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
- if (field.IsEmpty() || !field->IsExternal())
- return 0;
- void* ptr = field->Value();
- return (BSONObj*)ptr;
- }
-
- static void weakRefBSONCallback(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;
- Handle<External> field = Handle<External>::Cast(p->ToObject()->GetInternalField(0));
- BSONObj* data = (BSONObj*) field->Value();
- delete data;
- p.Dispose();
- }
-
- Persistent<v8::Object> V8Scope::wrapBSONObject(Local<v8::Object> obj, BSONObj* data) {
- obj->SetInternalField(0, v8::External::New(data));
- Persistent<v8::Object> p = Persistent<v8::Object>::New(obj);
- p.MakeWeak(this, weakRefBSONCallback);
- return p;
- }
-
- static void weakRefArrayCallback(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;
- Handle<External> field = Handle<External>::Cast(p->ToObject()->GetInternalField(0));
- char* data = (char*) field->Value();
- delete [] data;
- p.Dispose();
- }
-
- Persistent<v8::Object> V8Scope::wrapArrayObject(Local<v8::Object> obj, char* data) {
- obj->SetInternalField(0, v8::External::New(data));
- Persistent<v8::Object> p = Persistent<v8::Object>::New(obj);
- p.MakeWeak(this, weakRefArrayCallback);
- return p;
- }
-
- static Handle<v8::Value> namedGet(Local<v8::String> name, const v8::AccessorInfo &info) {
- // 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);
- BSONObj *obj = unwrapBSONObj(info.Holder());
- BSONElement elmt = obj->getField(key.c_str());
- if (elmt.eoo())
- return Handle<Value>();
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- val = scope->mongoToV8Element(elmt, false);
- info.This()->ForceSet(name, val);
-
- if (elmt.type() == mongo::Object || elmt.type() == mongo::Array) {
- // if accessing a subobject, it may get modified and base obj would not know
- // have to set base as modified, which means some optim is lost
- info.This()->SetHiddenValue(scope->V8STR_MODIFIED, v8::Boolean::New(true));
- }
- return val;
- }
-
- static Handle<v8::Value> namedGetRO(Local<v8::String> name, const v8::AccessorInfo &info) {
- string key = toSTLString(name);
- BSONObj *obj = unwrapBSONObj(info.Holder());
- BSONElement elmt = obj->getField(key.c_str());
- if (elmt.eoo())
- return Handle<Value>();
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- Handle<v8::Value> val = scope->mongoToV8Element(elmt, true);
- return val;
- }
-
- static Handle<v8::Value> namedSet(Local<v8::String> name, Local<v8::Value> value_obj, const v8::AccessorInfo& info) {
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- info.This()->SetHiddenValue(scope->V8STR_MODIFIED, v8::Boolean::New(true));
- 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;
- }
-
- Handle<Boolean> namedDelete( Local<v8::String> property, const AccessorInfo& info ) {
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- info.This()->SetHiddenValue(scope->V8STR_MODIFIED, v8::Boolean::New(true));
- return Handle<Boolean>();
- }
-
-// v8::Handle<v8::Integer> namedQuery(Local<v8::String> property, const AccessorInfo& info) {
-// string key = ToString(property);
-// return v8::Integer::New(None);
-// }
-
- 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());
- // 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());
- BSONElement elmt = obj->getField(key);
- if (elmt.eoo())
- return Handle<Value>();
- Handle<Value> val = scope->mongoToV8Element(elmt, false);
-// info.This()->ForceSet(name, val);
-
- if (elmt.type() == mongo::Object || elmt.type() == mongo::Array) {
- // if accessing a subobject, it may get modified and base obj would not know
- // have to set base as modified, which means some optim is lost
- info.This()->SetHiddenValue(scope->V8STR_MODIFIED, v8::Boolean::New(true));
- }
- return val;
- }
-
- Handle<Boolean> indexedDelete( uint32_t index, const AccessorInfo& info ) {
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- info.This()->SetHiddenValue(scope->V8STR_MODIFIED, v8::Boolean::New(true));
- return Handle<Boolean>();
- }
-
- static Handle<v8::Value> indexedGetRO(uint32_t index, const v8::AccessorInfo &info) {
- StringBuilder ss;
- ss << index;
- string key = ss.str();
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- // 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());
- BSONElement elmt = obj->getField(key);
- if (elmt.eoo())
- return Handle<Value>();
- Handle<Value> val = scope->mongoToV8Element(elmt, true);
-// info.This()->ForceSet(name, val);
- return val;
- }
-
- static Handle<v8::Value> indexedSet(uint32_t index, Local<v8::Value> value_obj, const v8::AccessorInfo& info) {
- Local< External > scp = External::Cast( *info.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
- info.This()->SetHiddenValue(scope->V8STR_MODIFIED, v8::Boolean::New(true));
- 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;
-// }
-
- Handle<Value> NamedReadOnlySet( Local<v8::String> property, Local<Value> value, const AccessorInfo& info ) {
- string key = toSTLString(property);
- cout << "cannot write property " << key << " to read-only object" << endl;
- return value;
- }
-
- Handle<Boolean> NamedReadOnlyDelete( Local<v8::String> property, const AccessorInfo& info ) {
- string key = toSTLString(property);
- cout << "cannot delete property " << key << " from read-only object" << endl;
- return Boolean::New( false );
- }
-
- Handle<Value> IndexedReadOnlySet( uint32_t index, Local<Value> value, const AccessorInfo& info ) {
- cout << "cannot write property " << index << " to read-only array" << endl;
- return value;
- }
-
- Handle<Boolean> IndexedReadOnlyDelete( uint32_t index, const AccessorInfo& info ) {
- cout << "cannot delete property " << index << " from read-only array" << endl;
- return Boolean::New( false );
- }
-
- // --- engine ---
-
- V8ScriptEngine::V8ScriptEngine() {
- }
-
- V8ScriptEngine::~V8ScriptEngine() {
- }
-
- void ScriptEngine::setup() {
- if ( !globalScriptEngine ) {
- globalScriptEngine = new V8ScriptEngine();
- }
- }
-
- 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 ) {
- V8::TerminateExecution( *i );
- }
- }
-
- // --- scope ---
-
- V8Scope::V8Scope( V8ScriptEngine * engine )
- : _engine( engine ) ,
- _connectState( NOT ) {
-
- V8Lock l;
- HandleScope handleScope;
- _context = Context::New();
- Context::Scope context_scope( _context );
- _global = Persistent< v8::Object >::New( _context->Global() );
- _emptyObj = Persistent< v8::Object >::New( v8::Object::New() );
-
- // initialize lazy object template
- lzObjectTemplate = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
- lzObjectTemplate->SetInternalFieldCount( 1 );
- lzObjectTemplate->SetNamedPropertyHandler(namedGet, namedSet, 0, namedDelete, 0, v8::External::New(this));
- lzObjectTemplate->SetIndexedPropertyHandler(indexedGet, indexedSet, 0, indexedDelete, 0, v8::External::New(this));
-
- roObjectTemplate = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
- roObjectTemplate->SetInternalFieldCount( 1 );
- roObjectTemplate->SetNamedPropertyHandler(namedGetRO, NamedReadOnlySet, 0, NamedReadOnlyDelete, namedEnumerator, v8::External::New(this));
- roObjectTemplate->SetIndexedPropertyHandler(indexedGetRO, IndexedReadOnlySet, 0, IndexedReadOnlyDelete, 0, v8::External::New(this));
-
- // initialize lazy array template
- // unfortunately it is not possible to create true v8 array from a template
- // this means we use an object template and copy methods over
- // 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, 0, v8::External::New(this));
-
- internalFieldObjects = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
- internalFieldObjects->SetInternalFieldCount( 1 );
-
- V8STR_CONN = getV8Str( "_conn" );
- V8STR_ID = getV8Str( "_id" );
- V8STR_LENGTH = getV8Str( "length" );
- V8STR_LEN = getV8Str( "len" );
- V8STR_TYPE = getV8Str( "type" );
- V8STR_ISOBJECTID = getV8Str( "isObjectId" );
- V8STR_RETURN = getV8Str( "return" );
- V8STR_ARGS = getV8Str( "args" );
- V8STR_T = getV8Str( "t" );
- V8STR_I = getV8Str( "i" );
- V8STR_EMPTY = getV8Str( "" );
- V8STR_MINKEY = getV8Str( "$MinKey" );
- V8STR_MAXKEY = getV8Str( "$MaxKey" );
- V8STR_NUMBERLONG = getV8Str( "__NumberLong" );
- V8STR_NUMBERINT = getV8Str( "__NumberInt" );
- V8STR_DBPTR = getV8Str( "__DBPointer" );
- V8STR_BINDATA = getV8Str( "__BinData" );
- V8STR_NATIVE_FUNC = getV8Str( "_native_function" );
- V8STR_NATIVE_DATA = getV8Str( "_native_data" );
- V8STR_V8_FUNC = getV8Str( "_v8_function" );
- V8STR_RO = getV8Str( "_ro" );
- V8STR_MODIFIED = getV8Str( "_mod" );
-
- injectV8Function("print", Print);
- injectV8Function("version", Version);
- injectV8Function("load", load);
-
- _wrapper = Persistent< v8::Function >::New( getObjectWrapperTemplate(this)->GetFunction() );
-
- injectV8Function("gc", GCV8);
-
- installDBTypes( this, _global );
- }
-
- V8Scope::~V8Scope() {
- V8Lock l;
- Context::Scope context_scope( _context );
- _wrapper.Dispose();
- _emptyObj.Dispose();
- for( unsigned i = 0; i < _funcs.size(); ++i )
- _funcs[ i ].Dispose();
- _funcs.clear();
- _global.Dispose();
- _context.Dispose();
- std::map <string, v8::Persistent <v8::String> >::iterator it = _strCache.begin();
- std::map <string, v8::Persistent <v8::String> >::iterator end = _strCache.end();
- while (it != end) {
- it->second.Dispose();
- ++it;
- }
- lzObjectTemplate.Dispose();
- lzArrayTemplate.Dispose();
- roObjectTemplate.Dispose();
- internalFieldObjects.Dispose();
- }
-
- /**
- * JS Callback that will call a c++ function with BSON arguments.
- */
- Handle< Value > V8Scope::nativeCallback( V8Scope* scope, const Arguments &args ) {
- V8Lock l;
- HandleScope handle_scope;
- Local< External > f = External::Cast( *args.Callee()->Get( scope->V8STR_NATIVE_FUNC ) );
- NativeFunction function = (NativeFunction)(f->Value());
- Local< External > data = External::Cast( *args.Callee()->Get( scope->V8STR_NATIVE_DATA ) );
- BSONObjBuilder b;
- for( int i = 0; i < args.Length(); ++i ) {
- stringstream ss;
- ss << i;
- scope->v8ToMongoElement( b, scope->V8STR_EMPTY, ss.str(), args[ i ] );
- }
- BSONObj nativeArgs = b.obj();
- BSONObj ret;
- try {
- ret = function( nativeArgs, data->Value() );
- }
- catch( const std::exception &e ) {
- return v8::ThrowException(v8::String::New(e.what()));
- }
- catch( ... ) {
- return v8::ThrowException(v8::String::New("unknown exception"));
- }
- return handle_scope.Close( scope->mongoToV8Element( ret.firstElement() ) );
- }
-
- Handle< Value > V8Scope::load( V8Scope* scope, const Arguments &args ) {
- Context::Scope context_scope(scope->_context);
- for (int i = 0; i < args.Length(); ++i) {
- std::string filename(toSTLString(args[i]));
- if (!scope->execFile(filename, false , true , false)) {
- return v8::ThrowException(v8::String::New((std::string("error loading file: ") + filename).c_str()));
- }
- }
- return v8::True();
- }
-
- /**
- * JS Callback that will call a c++ function with the v8 scope and v8 arguments.
- * Handles interrupts, exception handling, etc
- *
- * The implementation below assumes that SERVER-1816 has been fixed - in
- * particular, interrupted() must return true if an interrupt was ever
- * sent; currently that is not the case if a new killop overwrites the data
- * for an old one
- */
- v8::Handle< v8::Value > V8Scope::v8Callback( const v8::Arguments &args ) {
- disableV8Interrupt(); // we don't want to have to audit all v8 calls for termination exceptions, so we don't allow these exceptions during the callback
- if ( globalScriptEngine->interrupted() ) {
- v8::V8::TerminateExecution(); // experimentally it seems that TerminateExecution() will override the return value
- return v8::Undefined();
- }
- Local< External > f = External::Cast( *args.Callee()->Get( v8::String::New( "_v8_function" ) ) );
- v8Function function = (v8Function)(f->Value());
- Local< External > scp = External::Cast( *args.Data() );
- V8Scope* scope = (V8Scope*)(scp->Value());
-
- v8::Handle< v8::Value > ret;
- string exception;
- try {
- ret = function( scope, args );
- }
- catch( const std::exception &e ) {
- exception = e.what();
- }
- catch( ... ) {
- exception = "unknown exception";
- }
- enableV8Interrupt();
- if ( globalScriptEngine->interrupted() ) {
- v8::V8::TerminateExecution();
- return v8::Undefined();
- }
- if ( !exception.empty() ) {
- // technically, ThrowException is supposed to be the last v8 call before returning
- ret = v8::ThrowException( v8::String::New( exception.c_str() ) );
- }
- return ret;
- }
-
- // ---- global stuff ----
-
- void V8Scope::init( const BSONObj * data ) {
- V8Lock l;
- if ( ! data )
- return;
-
- BSONObjIterator i( *data );
- while ( i.more() ) {
- BSONElement e = i.next();
- setElement( e.fieldName() , e );
- }
- }
-
- void V8Scope::setNumber( const char * field , double val ) {
- V8_SIMPLE_HEADER
- _global->Set( getV8Str( field ) , v8::Number::New( val ) );
- }
-
- void V8Scope::setString( const char * field , const char * val ) {
- V8_SIMPLE_HEADER
- _global->Set( getV8Str( field ) , v8::String::New( val ) );
- }
-
- void V8Scope::setBoolean( const char * field , bool val ) {
- V8_SIMPLE_HEADER
- _global->Set( getV8Str( field ) , v8::Boolean::New( val ) );
- }
-
- void V8Scope::setElement( const char *field , const BSONElement& e ) {
- V8_SIMPLE_HEADER
- _global->Set( getV8Str( field ) , mongoToV8Element( e ) );
- }
-
- void V8Scope::setObject( const char *field , const BSONObj& obj , bool readOnly) {
- V8_SIMPLE_HEADER
- // 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( getV8Str( field ) , mongoToLZV8( obj, false, readOnly) );
- }
-
- int V8Scope::type( const char *field ) {
- V8_SIMPLE_HEADER
- 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;
- // needs to be explicit NumberInt to use integer
-// if ( v->IsInt32() )
-// return NumberInt;
- if ( v->IsNumber() )
- return NumberDouble;
- if ( v->IsExternal() ) {
- uassert( 10230 , "can't handle external yet" , 0 );
- return -1;
- }
- if ( v->IsDate() )
- return Date;
- if ( v->IsObject() )
- return Object;
-
- throw UserException( 12509, (string)"don't know what this is: " + field );
- }
-
- v8::Handle<v8::Value> V8Scope::get( const char * field ) {
- return _global->Get( getV8Str( field ) );
- }
-
- double V8Scope::getNumber( const char *field ) {
- V8_SIMPLE_HEADER
- return get( field )->ToNumber()->Value();
- }
-
- int V8Scope::getNumberInt( const char *field ) {
- V8_SIMPLE_HEADER
- return get( field )->ToInt32()->Value();
- }
-
- long long V8Scope::getNumberLongLong( const char *field ) {
- V8_SIMPLE_HEADER
- return get( field )->ToInteger()->Value();
- }
-
- string V8Scope::getString( const char *field ) {
- V8_SIMPLE_HEADER
- return toSTLString( get( field ) );
- }
-
- bool V8Scope::getBoolean( const char *field ) {
- V8_SIMPLE_HEADER
- return get( field )->ToBoolean()->Value();
- }
-
- BSONObj V8Scope::getObject( const char * field ) {
- V8_SIMPLE_HEADER
- Handle<Value> v = get( field );
- if ( v->IsNull() || v->IsUndefined() )
- return BSONObj();
- uassert( 10231 , "not an object" , v->IsObject() );
- return v8ToMongo( v->ToObject() );
- }
-
- // --- functions -----
-
- bool hasFunctionIdentifier( const string& code ) {
- if ( code.size() < 9 || code.find( "function" ) != 0 )
- return false;
-
- return code[8] == ' ' || code[8] == '(';
- }
-
- Local< v8::Function > V8Scope::__createFunction( const char * raw ) {
- raw = jsSkipWhiteSpace( raw );
- string code = raw;
- if ( !hasFunctionIdentifier( code ) ) {
- if ( code.find( "\n" ) == string::npos &&
- ! hasJSReturn( code ) &&
- ( 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;
- // this might be time consuming, consider allowing an interrupt
- 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 Local< v8::Function >();
- }
-
- Local<Value> result = script->Run();
- if ( result.IsEmpty() ) {
- _error = (string)"compile error: " + toSTLString( &try_catch );
- log() << _error << endl;
- return Local< v8::Function >();
- }
-
- return v8::Function::Cast( *_global->Get( v8::String::New( fn.c_str() ) ) );
- }
-
- ScriptingFunction V8Scope::_createFunction( const char * raw ) {
- V8_SIMPLE_HEADER
- Local< Value > ret = __createFunction( raw );
- if ( ret.IsEmpty() )
- return 0;
- Persistent<Value> f = Persistent< Value >::New( ret );
- uassert( 10232, "not a func" , f->IsFunction() );
- int num = _funcs.size() + 1;
- _funcs.push_back( f );
- return num;
- }
-
- void V8Scope::setFunction( const char *field , const char * code ) {
- V8_SIMPLE_HEADER
- _global->Set( getV8Str( field ) , __createFunction(code) );
- }
-
-// 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;
- Handle<v8::String> f = getV8Str( from );
- Handle<v8::String> t = getV8Str( to );
- _global->Set( t , _global->Get( f ) );
- _global->Set( f , v8::Undefined() );
- }
-
- int V8Scope::invoke( ScriptingFunction func , const BSONObj* argsObject, const BSONObj* recv, int timeoutMs , bool ignoreReturn, bool readOnlyArgs, bool readOnlyRecv ) {
- V8_SIMPLE_HEADER
- Handle<Value> funcValue = _funcs[func-1];
-
- TryCatch try_catch;
- int nargs = argsObject ? argsObject->nFields() : 0;
- scoped_array< 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[i] = mongoToV8Element( next, readOnlyArgs );
- }
- setObject( "args", *argsObject, readOnlyArgs); // for backwards compatibility
- }
- else {
- _global->Set( V8STR_ARGS, v8::Undefined() );
- }
- if ( globalScriptEngine->interrupted() ) {
- stringstream ss;
- ss << "error in invoke: " << globalScriptEngine->checkInterrupt();
- _error = ss.str();
- log() << _error << endl;
- return 1;
- }
- Handle<v8::Object> v8recv;
- if (recv != 0)
- v8recv = mongoToLZV8(*recv, false, readOnlyRecv);
- else
- v8recv = _emptyObj;
-
- enableV8Interrupt(); // because of v8 locker we can check interrupted, then enable
- Local<Value> result = ((v8::Function*)(*funcValue))->Call( v8recv , nargs , nargs ? args.get() : 0 );
- disableV8Interrupt();
-
- if ( result.IsEmpty() ) {
- stringstream ss;
- if ( try_catch.HasCaught() && !try_catch.CanContinue() ) {
- ss << "error in invoke: " << globalScriptEngine->checkInterrupt();
- }
- else {
- ss << "error in invoke: " << toSTLString( &try_catch );
- }
- _error = ss.str();
- log() << _error << endl;
- return 1;
- }
-
- if ( ! ignoreReturn ) {
- _global->Set( V8STR_RETURN , result );
- }
-
- return 0;
- }
-
- bool V8Scope::exec( const StringData& 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 code: " << code << endl;
- t = 0;
- }
- }
-
- V8_SIMPLE_HEADER
-
- TryCatch try_catch;
-
- Handle<Script> script = v8::Script::Compile( v8::String::New( code.data() ) ,
- 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( 10233 , _error , 0 );
- return false;
- }
-
- 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
- Handle<v8::Value> result = script->Run();
- disableV8Interrupt();
- if ( result.IsEmpty() ) {
- if ( try_catch.HasCaught() && !try_catch.CanContinue() ) {
- _error = (string)"exec error: " + globalScriptEngine->checkInterrupt();
- }
- else {
- _error = (string)"exec error: " + toSTLString( &try_catch );
- }
- if ( reportError )
- log() << _error << endl;
- if ( assertOnError )
- uassert( 10234 , _error , 0 );
- return false;
- }
-
- _global->Set( getV8Str( "__lastres__" ) , result );
-
- if ( printResult && ! result->IsUndefined() ) {
- cout << toSTLString( result ) << endl;
- }
-
- return true;
- }
-
- void V8Scope::injectNative( const char *field, NativeFunction func, void* data ) {
- injectNative(field, func, _global, data);
- }
-
- void V8Scope::injectNative( const char *field, NativeFunction func, Handle<v8::Object>& obj, void* data ) {
- V8_SIMPLE_HEADER
-
- Handle< FunctionTemplate > ft = createV8Function(nativeCallback);
- ft->Set( this->V8STR_NATIVE_FUNC, External::New( (void*)func ) );
- ft->Set( this->V8STR_NATIVE_DATA, External::New( data ) );
- obj->Set( getV8Str( field ), ft->GetFunction() );
- }
-
- void V8Scope::injectV8Function( const char *field, v8Function func ) {
- injectV8Function(field, func, _global);
- }
-
- void V8Scope::injectV8Function( const char *field, v8Function func, Handle<v8::Object>& obj ) {
- V8_SIMPLE_HEADER
-
- Handle< FunctionTemplate > ft = createV8Function(func);
- Handle<v8::Function> f = ft->GetFunction();
- obj->Set( getV8Str( field ), f );
- }
-
- void V8Scope::injectV8Function( const char *field, v8Function func, Handle<v8::Template>& t ) {
- V8_SIMPLE_HEADER
-
- Handle< FunctionTemplate > ft = createV8Function(func);
- Handle<v8::Function> f = ft->GetFunction();
- t->Set( getV8Str( field ), f );
- }
-
- Handle<FunctionTemplate> V8Scope::createV8Function( v8Function func ) {
- Handle< FunctionTemplate > ft = v8::FunctionTemplate::New(v8Callback, External::New( this ));
- ft->Set( this->V8STR_V8_FUNC, External::New( (void*)func ) );
- return ft;
- }
-
- void V8Scope::gc() {
- cout << "in gc" << endl;
- V8Lock l;
- while( !V8::IdleNotification() );
- }
-
- // ----- db access -----
-
- void V8Scope::localConnect( const char * dbName ) {
- {
- V8_SIMPLE_HEADER
-
- if ( _connectState == EXTERNAL )
- throw UserException( 12510, "externalSetup already called, can't call externalSetup" );
- if ( _connectState == LOCAL ) {
- if ( _localDBName == dbName )
- return;
- throw UserException( 12511, "localConnect called with a different name previously" );
- }
-
- // needed for killop / interrupt support
- v8::Locker::StartPreemption( 50 );
-
- //_global->Set( v8::String::New( "Mongo" ) , _engine->_externalTemplate->GetFunction() );
- _global->Set( getV8Str( "Mongo" ) , getMongoFunctionTemplate( this, 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;
- }
- loadStored();
- }
-
- void V8Scope::externalSetup() {
- V8_SIMPLE_HEADER
- if ( _connectState == EXTERNAL )
- return;
- if ( _connectState == LOCAL )
- throw UserException( 12512, "localConnect already called, can't call externalSetup" );
-
- installFork( this, _global, _context );
- _global->Set( getV8Str( "Mongo" ) , getMongoFunctionTemplate( this, false )->GetFunction() );
- execCoreFiles();
- _connectState = EXTERNAL;
- }
-
- // ----- internal -----
-
- void V8Scope::reset() {
- _startCall();
- }
-
- void V8Scope::_startCall() {
- _error = "";
- }
-
- Local< v8::Value > newFunction( const char *code ) {
- stringstream codeSS;
- codeSS << "____MontoToV8_newFunction_temp = " << code;
- string codeStr = codeSS.str();
- Local< Script > compiled = Script::New( v8::String::New( codeStr.c_str() ) );
- Local< Value > ret = compiled->Run();
- return ret;
- }
-
- Local< v8::Value > V8Scope::newId( const OID &id ) {
- v8::Function * idCons = this->getObjectIdCons();
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::String::New( id.str().c_str() );
- return idCons->NewInstance( 1 , argv );
- }
-
- Local<v8::Object> V8Scope::mongoToV8( const BSONObj& m , bool array, bool readOnly ) {
-
- Local<v8::Object> o;
-
- // handle DBRef. needs to come first. isn't it? (metagoto)
- static string ref = "$ref";
- if ( ref == m.firstElement().fieldName() ) {
- const BSONElement& id = m["$id"];
- if (!id.eoo()) { // there's no check on $id exitence in sm implementation. risky ?
- v8::Function* dbRef = getNamedCons( "DBRef" );
- o = dbRef->NewInstance();
- }
- }
-
- Local< v8::ObjectTemplate > readOnlyObjects;
-
- if ( !o.IsEmpty() ) {
- readOnly = false;
- }
- else if ( array ) {
- // NOTE Looks like it's impossible to add interceptors to v8 arrays.
- readOnly = false;
- o = v8::Array::New();
- }
- else if ( !readOnly ) {
- o = v8::Object::New();
- }
- else {
- // NOTE Our readOnly implemention relies on undocumented ObjectTemplate
- // functionality that may be fragile, but it still seems like the best option
- // for now -- fwiw, the v8 docs are pretty sparse. I've determined experimentally
- // that when property handlers are set for an object template, they will attach
- // to objects previously created by that template. To get this to work, though,
- // it is necessary to initialize the template's property handlers before
- // creating objects from the template (as I have in the following few lines
- // of code).
- // NOTE In my first attempt, I configured the permanent property handlers before
- // constructiong the object and replaced the Set() calls below with ForceSet().
- // However, it turns out that ForceSet() only bypasses handlers for named
- // properties and not for indexed properties.
- readOnlyObjects = v8::ObjectTemplate::New();
- // NOTE This internal field will store type info for special db types. For
- // regular objects the field is unnecessary - for simplicity I'm creating just
- // one readOnlyObjects template for objects where the field is & isn't necessary,
- // assuming that the overhead of an internal field is slight.
- readOnlyObjects->SetInternalFieldCount( 1 );
- readOnlyObjects->SetNamedPropertyHandler( 0 );
- readOnlyObjects->SetIndexedPropertyHandler( 0 );
- o = readOnlyObjects->NewInstance();
- }
-
- mongo::BSONObj sub;
-
- for ( BSONObjIterator i(m); i.more(); ) {
- const BSONElement& f = i.next();
-
- Local<Value> v;
- Handle<v8::String> name = getV8Str(f.fieldName());
-
- switch ( f.type() ) {
-
- case mongo::Code:
- o->Set( name, newFunction( f.valuestr() ) );
- break;
-
- case CodeWScope:
- if ( f.codeWScopeObject().isEmpty() )
- log() << "warning: CodeWScope doesn't transfer to db.eval" << endl;
- o->Set( name, newFunction( f.codeWScopeCode() ) );
- break;
-
- case mongo::String:
- o->Set( name , v8::String::New( f.valuestr() ) );
- break;
-
- case mongo::jstOID: {
- v8::Function * idCons = getObjectIdCons();
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::String::New( f.__oid().str().c_str() );
- o->Set( name ,
- idCons->NewInstance( 1 , argv ) );
- break;
- }
-
- case mongo::NumberDouble:
- case mongo::NumberInt:
- o->Set( name , v8::Number::New( f.number() ) );
- break;
-
-// case mongo::NumberInt: {
-// Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
-// int val = f.numberInt();
-// v8::Function* numberInt = getNamedCons( "NumberInt" );
-// v8::Handle<v8::Value> argv[1];
-// argv[0] = v8::Int32::New( val );
-// o->Set( name, numberInt->NewInstance( 1, argv ) );
-// break;
-// }
-
- case mongo::Array:
- sub = f.embeddedObject();
- o->Set( name , mongoToV8( sub , true, readOnly ) );
- break;
- case mongo::Object:
- sub = f.embeddedObject();
- o->Set( name , mongoToLZV8( sub , false, readOnly ) );
- break;
-
- case mongo::Date:
- o->Set( name , v8::Date::New( (double) ((long long)f.date().millis) ));
- break;
-
- case mongo::Bool:
- o->Set( name , v8::Boolean::New( f.boolean() ) );
- break;
-
- case mongo::jstNULL:
- case mongo::Undefined: // duplicate sm behavior
- o->Set( name , v8::Null() );
- break;
-
- case mongo::RegEx: {
- v8::Function * regex = getNamedCons( "RegExp" );
-
- v8::Handle<v8::Value> argv[2];
- argv[0] = v8::String::New( f.regex() );
- argv[1] = v8::String::New( f.regexFlags() );
-
- o->Set( name , regex->NewInstance( 2 , argv ) );
- break;
- }
-
- case mongo::BinData: {
- /*Local<v8::Object> b = */ readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
-
- int len;
- const char *data = f.binData( len );
-
- v8::Function* binData = getNamedCons( "BinData" );
- v8::Handle<v8::Value> argv[3];
- argv[0] = v8::Number::New( len );
- argv[1] = v8::Number::New( f.binDataType() );
- argv[2] = v8::String::New( data, len );
- o->Set( name, binData->NewInstance(3, argv) );
- break;
- }
-
- case mongo::Timestamp: {
- Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
-
- sub->Set( V8STR_T , v8::Number::New( f.timestampTime() ) );
- sub->Set( V8STR_I , v8::Number::New( f.timestampInc() ) );
- sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
-
- o->Set( name , sub );
- break;
- }
-
- case mongo::NumberLong: {
- /* Local<v8::Object> sub = */ readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
- unsigned long long val = f.numberLong();
- v8::Function* numberLong = getNamedCons( "NumberLong" );
- double floatApprox = (double)(long long)val;
- if ( (long long)val == (long long)floatApprox ) {
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::Number::New( floatApprox );
- o->Set( name, numberLong->NewInstance( 1, argv ) );
- }
- else {
- v8::Handle<v8::Value> argv[3];
- argv[0] = v8::Number::New( floatApprox );
- argv[1] = v8::Integer::New( val >> 32 );
- argv[2] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) );
- o->Set( name, numberLong->NewInstance(3, argv) );
- }
- break;
- }
-
- case mongo::MinKey: {
- Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
- sub->Set( V8STR_MINKEY, v8::Boolean::New( true ) );
- sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
- o->Set( name , sub );
- break;
- }
-
- case mongo::MaxKey: {
- Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
- sub->Set( V8STR_MAXKEY, v8::Boolean::New( true ) );
- sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
- o->Set( name , sub );
- break;
- }
-
- case mongo::DBRef: {
- v8::Function* dbPointer = getNamedCons( "DBPointer" );
- v8::Handle<v8::Value> argv[2];
- argv[0] = getV8Str( f.dbrefNS() );
- argv[1] = newId( f.dbrefOID() );
- o->Set( name, dbPointer->NewInstance(2, argv) );
- break;
- }
-
- default:
- cout << "can't handle type: ";
- cout << f.type() << " ";
- cout << f.toString();
- cout << endl;
- break;
- }
-
- }
-
- if ( readOnly ) {
- readOnlyObjects->SetNamedPropertyHandler( 0, NamedReadOnlySet, 0, NamedReadOnlyDelete );
- readOnlyObjects->SetIndexedPropertyHandler( 0, IndexedReadOnlySet, 0, IndexedReadOnlyDelete );
- }
-
- return o;
- }
-
- /**
- * converts a BSONObj to a Lazy V8 object
- */
- Handle<v8::Object> V8Scope::mongoToLZV8( const BSONObj& m , bool array, bool readOnly ) {
- Local<v8::Object> o;
-
- if (readOnly) {
- o = roObjectTemplate->NewInstance();
- o->SetHiddenValue(V8STR_RO, v8::Boolean::New(true));
- } else {
- if (array) {
- o = lzArrayTemplate->NewInstance();
- o->SetPrototype(v8::Array::New(1)->GetPrototype());
- o->Set(V8STR_LENGTH, v8::Integer::New(m.nFields()), DontEnum);
- // o->Set(ARRAY_STRING, v8::Boolean::New(true), DontEnum);
- } else {
- o = lzObjectTemplate->NewInstance();
-
- static string ref = "$ref";
- if ( ref == m.firstElement().fieldName() ) {
- const BSONElement& id = m["$id"];
- if (!id.eoo()) {
- v8::Function* dbRef = getNamedCons( "DBRef" );
- o->SetPrototype(dbRef->NewInstance()->GetPrototype());
- }
- }
- }
-
- // 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());
- }
- }
-
- BSONObj* own = new BSONObj(m.getOwned());
-// BSONObj* own = new BSONObj(m);
- Persistent<v8::Object> p = wrapBSONObject(o, own);
- return p;
- }
-
- Handle<v8::Value> V8Scope::mongoToV8Element( const BSONElement &f, bool readOnly ) {
-// Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New();
-// internalFieldObjects->SetInternalFieldCount( 1 );
-
- switch ( f.type() ) {
-
- case mongo::Code:
- return newFunction( f.valuestr() );
-
- case CodeWScope:
- if ( f.codeWScopeObject().isEmpty() )
- log() << "warning: CodeWScope doesn't transfer to db.eval" << endl;
- return newFunction( f.codeWScopeCode() );
-
- case mongo::String:
-// return v8::String::NewExternal( new ExternalString( f.valuestr() ));
- return v8::String::New( f.valuestr() );
-// return getV8Str( f.valuestr() );
-
- case mongo::jstOID:
- return newId( f.__oid() );
-
- case mongo::NumberDouble:
- case mongo::NumberInt:
- return v8::Number::New( f.number() );
-
- case mongo::Array:
- // for arrays it's better to use non lazy object because:
- // - 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() , true, readOnly );
- case mongo::Object:
- return mongoToLZV8( f.embeddedObject() , false, readOnly);
-
- case mongo::Date:
- return v8::Date::New( (double) ((long long)f.date().millis) );
-
- case mongo::Bool:
- return v8::Boolean::New( f.boolean() );
-
- case mongo::EOO:
- case mongo::jstNULL:
- case mongo::Undefined: // duplicate sm behavior
- return v8::Null();
-
- case mongo::RegEx: {
- v8::Function * regex = getNamedCons( "RegExp" );
-
- v8::Handle<v8::Value> argv[2];
- argv[0] = v8::String::New( f.regex() );
- argv[1] = v8::String::New( f.regexFlags() );
-
- return regex->NewInstance( 2 , argv );
- break;
- }
-
- case mongo::BinData: {
- int len;
- const char *data = f.binData( len );
-
- v8::Function* binData = getNamedCons( "BinData" );
- v8::Handle<v8::Value> argv[3];
- argv[0] = v8::Number::New( len );
- argv[1] = v8::Number::New( f.binDataType() );
- argv[2] = v8::String::New( data, len );
- return binData->NewInstance( 3, argv );
- };
-
- case mongo::Timestamp: {
- Local<v8::Object> sub = internalFieldObjects->NewInstance();
-
- sub->Set( V8STR_T , v8::Number::New( f.timestampTime() ) );
- sub->Set( V8STR_I , v8::Number::New( f.timestampInc() ) );
- sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
-
- return sub;
- }
-
- case mongo::NumberLong: {
- /* Local<v8::Object> sub = */ internalFieldObjects->NewInstance();
- unsigned long long val = f.numberLong();
- v8::Function* numberLong = getNamedCons( "NumberLong" );
- if ( (long long)val == (long long)(double)(long long)(val) ) {
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::Number::New( (double)(long long)( val ) );
- return numberLong->NewInstance( 1, argv );
- }
- else {
- v8::Handle<v8::Value> argv[3];
- argv[0] = v8::Number::New( (double)(long long)( val ) );
- argv[1] = v8::Integer::New( val >> 32 );
- argv[2] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) );
- return numberLong->NewInstance( 3, argv );
- }
- }
-
-// case mongo::NumberInt: {
-// Local<v8::Object> sub = internalFieldObjects->NewInstance();
-// int val = f.numberInt();
-// v8::Function* numberInt = getNamedCons( "NumberInt" );
-// v8::Handle<v8::Value> argv[1];
-// argv[0] = v8::Int32::New(val);
-// return numberInt->NewInstance( 1, argv );
-// }
-
- case mongo::MinKey: {
- Local<v8::Object> sub = internalFieldObjects->NewInstance();
- sub->Set( V8STR_MINKEY, v8::Boolean::New( true ) );
- sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
- return sub;
- }
-
- case mongo::MaxKey: {
- Local<v8::Object> sub = internalFieldObjects->NewInstance();
- sub->Set( V8STR_MAXKEY, v8::Boolean::New( true ) );
- sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
- return sub;
- }
-
- case mongo::DBRef: {
- v8::Function* dbPointer = getNamedCons( "DBPointer" );
- v8::Handle<v8::Value> argv[2];
- argv[0] = getV8Str( f.dbrefNS() );
- argv[1] = newId( f.dbrefOID() );
- return dbPointer->NewInstance(2, argv);
- }
-
- default:
- cout << "can't handle type: ";
- cout << f.type() << " ";
- cout << f.toString();
- cout << endl;
- break;
- }
-
- return v8::Undefined();
- }
-
- void V8Scope::append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName ) {
- V8_SIMPLE_HEADER
- Handle<v8::String> v8name = getV8Str(scopeName);
- Handle<Value> value = _global->Get( v8name );
- v8ToMongoElement(builder, v8name, fieldName, value);
- }
-
- void V8Scope::v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , const string sname , v8::Handle<v8::Value> value , int depth, BSONObj* originalParent ) {
-
- if ( value->IsString() ) {
-// Handle<v8::String> str = Handle<v8::String>::Cast(value);
-// ExternalString* es = (ExternalString*) (str->GetExternalAsciiStringResource());
-// b.append( sname , es->data() );
- b.append( sname , toSTLString( value ).c_str() );
- return;
- }
-
- if ( value->IsFunction() ) {
- b.appendCode( sname , toSTLString( value ) );
- return;
- }
-
- if ( value->IsNumber() ) {
- double val = value->ToNumber()->Value();
- // if previous type was integer, keep it
- int intval = (int)val;
- if (val == intval && originalParent) {
- BSONElement elmt = originalParent->getField(sname);
- if (elmt.type() == mongo::NumberInt) {
- b.append( sname , intval );
- return;
- }
- }
-
- b.append( sname , val );
- return;
- }
-
- if ( value->IsArray() ) {
- BSONObj sub = v8ToMongo( value->ToObject() , depth );
- b.appendArray( sname , sub );
- return;
- }
-
- if ( value->IsDate() ) {
- long long dateval = (long long)(v8::Date::Cast( *value )->NumberValue());
- b.appendDate( sname , Date_t( (unsigned long long) dateval ) );
- return;
- }
-
- if ( value->IsExternal() )
- return;
-
- if ( value->IsObject() ) {
- // The user could potentially modify the fields of these special objects,
- // wreaking havoc when we attempt to reinterpret them. Not doing any validation
- // for now...
- Local< v8::Object > obj = value->ToObject();
- if ( obj->InternalFieldCount() && obj->GetInternalField( 0 )->IsNumber() ) {
- switch( obj->GetInternalField( 0 )->ToInt32()->Value() ) { // NOTE Uint32's Value() gave me a linking error, so going with this instead
- case Timestamp:
- b.appendTimestamp( sname,
- Date_t( (unsigned long long)(obj->Get( V8STR_T )->ToNumber()->Value() )),
- obj->Get( V8STR_I )->ToInt32()->Value() );
- return;
- case MinKey:
- b.appendMinKey( sname );
- return;
- case MaxKey:
- b.appendMaxKey( sname );
- return;
- default:
- assert( "invalid internal field" == 0 );
- }
- }
- string s = toSTLString( value );
- if ( s.size() && s[0] == '/' ) {
- s = s.substr( 1 );
- string r = s.substr( 0 , s.rfind( "/" ) );
- string o = s.substr( s.rfind( "/" ) + 1 );
- b.appendRegex( sname , r , o );
- }
- else if ( value->ToObject()->GetPrototype()->IsObject() &&
- value->ToObject()->GetPrototype()->ToObject()->HasRealNamedProperty( V8STR_ISOBJECTID ) ) {
- OID oid;
- oid.init( toSTLString( value ) );
- b.appendOID( sname , &oid );
- }
- else if ( !value->ToObject()->GetHiddenValue( V8STR_NUMBERLONG ).IsEmpty() ) {
- // TODO might be nice to potentially speed this up with an indexed internal
- // field, but I don't yet know how to use an ObjectTemplate with a
- // constructor.
- v8::Handle< v8::Object > it = value->ToObject();
- long long val;
- if ( !it->Has( getV8Str( "top" ) ) ) {
- val = (long long)( it->Get( getV8Str( "floatApprox" ) )->NumberValue() );
- }
- else {
- val = (long long)
- ( (unsigned long long)( it->Get( getV8Str( "top" ) )->ToInt32()->Value() ) << 32 ) +
- (unsigned)( it->Get( getV8Str( "bottom" ) )->ToInt32()->Value() );
- }
-
- b.append( sname, val );
- }
- else if ( !value->ToObject()->GetHiddenValue( V8STR_NUMBERINT ).IsEmpty() ) {
- v8::Handle< v8::Object > it = value->ToObject();
- b.append(sname, it->GetHiddenValue(V8STR_NUMBERINT)->Int32Value());
- }
- else if ( !value->ToObject()->GetHiddenValue( V8STR_DBPTR ).IsEmpty() ) {
- OID oid;
- oid.init( toSTLString( value->ToObject()->Get( getV8Str( "id" ) ) ) );
- string ns = toSTLString( value->ToObject()->Get( getV8Str( "ns" ) ) );
- b.appendDBRef( sname, ns, oid );
- }
- else if ( !value->ToObject()->GetHiddenValue( V8STR_BINDATA ).IsEmpty() ) {
- int len = obj->Get( getV8Str( "len" ) )->ToInt32()->Value();
- Local<External> c = External::Cast( *(obj->GetInternalField( 0 )) );
- const char* dataArray = (char*)(c->Value());;
- b.appendBinData( sname,
- len,
- mongo::BinDataType( obj->Get( getV8Str( "type" ) )->ToInt32()->Value() ),
- dataArray );
- }
- else {
- BSONObj sub = v8ToMongo( value->ToObject() , depth );
- b.append( sname , sub );
- }
- return;
- }
-
- if ( value->IsBoolean() ) {
- b.appendBool( sname , value->ToBoolean()->Value() );
- return;
- }
-
- else if ( value->IsUndefined() ) {
- b.appendUndefined( sname );
- return;
- }
-
- else if ( value->IsNull() ) {
- b.appendNull( sname );
- return;
- }
-
- cout << "don't know how to convert to mongo field [" << name << "]\t" << value << endl;
- }
-
- BSONObj V8Scope::v8ToMongo( v8::Handle<v8::Object> o , int depth ) {
- BSONObj* originalBSON = 0;
- if (o->HasNamedLookupInterceptor()) {
- originalBSON = unwrapBSONObj(o);
- }
-
- if ( !o->GetHiddenValue( V8STR_RO ).IsEmpty() ||
- (o->HasNamedLookupInterceptor() && o->GetHiddenValue( V8STR_MODIFIED ).IsEmpty()) ) {
- // object was readonly, use bson as is
- if (originalBSON)
- return *originalBSON;
- }
-
- BSONObjBuilder b;
-
- if ( depth == 0 ) {
- if ( o->HasRealNamedProperty( V8STR_ID ) ) {
- v8ToMongoElement( b , V8STR_ID , "_id" , o->Get( V8STR_ID ), 0, originalBSON );
- }
- }
-
- Local<v8::Array> names = o->GetPropertyNames();
- for ( unsigned int i=0; i<names->Length(); i++ ) {
- v8::Local<v8::String> name = names->Get( 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 ( depth == 0 && sname == "_id" )
- continue;
-
- v8ToMongoElement( b , name , sname , value , depth + 1, originalBSON );
- }
- return b.obj();
- }
-
- // --- random utils ----
-
- v8::Function * V8Scope::getNamedCons( const char * name ) {
- return v8::Function::Cast( *(v8::Context::GetCurrent()->Global()->Get( getV8Str( name ) ) ) );
- }
-
- v8::Function * V8Scope::getObjectIdCons() {
- return getNamedCons( "ObjectId" );
- }
-
- Handle<v8::Value> V8Scope::Print(V8Scope* scope, const Arguments& args) {
- bool first = true;
- for (int i = 0; i < args.Length(); i++) {
- HandleScope handle_scope;
- if (first) {
- first = false;
- }
- else {
- printf(" ");
- }
- v8::String::Utf8Value str(args[i]);
- printf("%s", *str);
- }
- printf("\n");
- return v8::Undefined();
- }
-
- Handle<v8::Value> V8Scope::Version(V8Scope* scope, const Arguments& args) {
- HandleScope handle_scope;
- return handle_scope.Close( v8::String::New(v8::V8::GetVersion()) );
- }
-
- Handle<v8::Value> V8Scope::GCV8(V8Scope* scope, const Arguments& args) {
- V8Lock l;
- while( !V8::IdleNotification() );
- return v8::Undefined();
- }
-
- /**
- * Gets a V8 strings from the scope's cache, creating one if needed
- */
- v8::Handle<v8::String> V8Scope::getV8Str(string str) {
- Persistent<v8::String> ptr = _strCache[str];
- if (ptr.IsEmpty()) {
- ptr = Persistent<v8::String>::New(v8::String::New(str.c_str()));
- _strCache[str] = ptr;
-// cout << "Adding str " + str << endl;
- }
-// cout << "Returning str " + str << endl;
- return ptr;
- }
-
-} // namespace mongo
diff --git a/scripting/engine_v8.h b/scripting/engine_v8.h
deleted file mode 100644
index 3f116c9c2c2..00000000000
--- a/scripting/engine_v8.h
+++ /dev/null
@@ -1,231 +0,0 @@
-//engine_v8.h
-
-/* 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.
- */
-
-#pragma once
-
-#include <vector>
-#include "engine.h"
-#include <v8.h>
-
-using namespace v8;
-
-namespace mongo {
-
- class V8ScriptEngine;
- class V8Scope;
-
- typedef Handle< Value > (*v8Function) ( V8Scope* scope, const v8::Arguments& args );
-
- // Preemption is going to be allowed for the v8 mutex, and some of our v8
- // usage is not preemption safe. So we are using an additional mutex that
- // will not be preempted. The V8Lock should be used in place of v8::Locker
- // except in certain special cases involving interrupts.
- namespace v8Locks {
- // the implementations are quite simple - objects must be destroyed in
- // reverse of the order created, and should not be shared between threads
- struct RecursiveLock {
- RecursiveLock();
- ~RecursiveLock();
- bool _unlock;
- };
- struct RecursiveUnlock {
- RecursiveUnlock();
- ~RecursiveUnlock();
- bool _lock;
- };
- } // namespace v8Locks
- class V8Lock {
- v8Locks::RecursiveLock _noPreemptionLock;
- v8::Locker _preemptionLock;
- };
- struct V8Unlock {
- v8::Unlocker _preemptionUnlock;
- v8Locks::RecursiveUnlock _noPreemptionUnlock;
- };
-
- class V8Scope : public Scope {
- public:
-
- V8Scope( V8ScriptEngine * engine );
- ~V8Scope();
-
- virtual void reset();
- virtual void init( const BSONObj * data );
-
- virtual void localConnect( const char * dbName );
- virtual void externalSetup();
-
- v8::Handle<v8::Value> get( const char * field ); // caller must create context and handle scopes
- virtual double getNumber( const char *field );
- virtual int getNumberInt( const char *field );
- virtual long long getNumberLongLong( const char *field );
- virtual string getString( const char *field );
- virtual bool getBoolean( const char *field );
- virtual BSONObj getObject( const char *field );
- Handle<v8::Object> getGlobalObject() { return _global; };
-
- virtual int type( const char *field );
-
- virtual void setNumber( const char *field , double val );
- virtual void setString( const char *field , const char * val );
- 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 setFunction( const char *field , const char * code );
-// 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, const BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool readOnlyArgs = false, bool readOnlyRecv = false );
- virtual bool exec( const StringData& code , const string& name , bool printResult , bool reportError , bool assertOnError, int timeoutMs );
- virtual string getError() { return _error; }
-
- virtual void injectNative( const char *field, NativeFunction func, void* data = 0 );
- void injectNative( const char *field, NativeFunction func, Handle<v8::Object>& obj, void* data = 0 );
- void injectV8Function( const char *field, v8Function func );
- void injectV8Function( const char *field, v8Function func, Handle<v8::Object>& obj );
- void injectV8Function( const char *field, v8Function func, Handle<v8::Template>& t );
- Handle<v8::FunctionTemplate> createV8Function( v8Function func );
-
- void gc();
-
- Handle< Context > context() const { return _context; }
-
- v8::Local<v8::Object> mongoToV8( 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, BSONObj* originalParent=0 );
- v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool readOnly = false );
- virtual void append( BSONObjBuilder & builder , const char * fieldName , const char * scopeName );
-
- v8::Function * getNamedCons( const char * name );
- v8::Function * getObjectIdCons();
- Local< v8::Value > newId( const OID &id );
-
- Persistent<v8::Object> wrapBSONObject(Local<v8::Object> obj, BSONObj* data);
- Persistent<v8::Object> wrapArrayObject(Local<v8::Object> obj, char* data);
-
- v8::Handle<v8::String> getV8Str(string str);
-// inline v8::Handle<v8::String> getV8Str(string str) { return v8::String::New(str.c_str()); }
- inline v8::Handle<v8::String> getLocalV8Str(string str) { return v8::String::New(str.c_str()); }
-
- Handle<v8::String> V8STR_CONN;
- Handle<v8::String> V8STR_ID;
- Handle<v8::String> V8STR_LENGTH;
- Handle<v8::String> V8STR_LEN;
- Handle<v8::String> V8STR_TYPE;
- Handle<v8::String> V8STR_ISOBJECTID;
- Handle<v8::String> V8STR_NATIVE_FUNC;
- Handle<v8::String> V8STR_NATIVE_DATA;
- Handle<v8::String> V8STR_V8_FUNC;
- Handle<v8::String> V8STR_RETURN;
- Handle<v8::String> V8STR_ARGS;
- Handle<v8::String> V8STR_T;
- Handle<v8::String> V8STR_I;
- Handle<v8::String> V8STR_EMPTY;
- Handle<v8::String> V8STR_MINKEY;
- Handle<v8::String> V8STR_MAXKEY;
- Handle<v8::String> V8STR_NUMBERLONG;
- Handle<v8::String> V8STR_NUMBERINT;
- Handle<v8::String> V8STR_DBPTR;
- Handle<v8::String> V8STR_BINDATA;
- Handle<v8::String> V8STR_WRAPPER;
- Handle<v8::String> V8STR_RO;
- Handle<v8::String> V8STR_MODIFIED;
-
- private:
- void _startCall();
-
- static Handle< Value > nativeCallback( V8Scope* scope, const Arguments &args );
- static v8::Handle< v8::Value > v8Callback( const v8::Arguments &args );
- static Handle< Value > load( V8Scope* scope, const Arguments &args );
- static Handle< Value > Print(V8Scope* scope, const v8::Arguments& args);
- static Handle< Value > Version(V8Scope* scope, const v8::Arguments& args);
- static Handle< Value > GCV8(V8Scope* scope, const v8::Arguments& args);
-
-
- V8ScriptEngine * _engine;
-
- Persistent<Context> _context;
- Persistent<v8::Object> _global;
-
- string _error;
- vector< Persistent<Value> > _funcs;
- v8::Persistent<v8::Object> _emptyObj;
-
- v8::Persistent<v8::Function> _wrapper;
-
- enum ConnectState { NOT , LOCAL , EXTERNAL };
- ConnectState _connectState;
-
- std::map <string, v8::Persistent <v8::String> > _strCache;
-
- Persistent<v8::ObjectTemplate> lzObjectTemplate;
- Persistent<v8::ObjectTemplate> roObjectTemplate;
- Persistent<v8::ObjectTemplate> lzArrayTemplate;
- Persistent<v8::ObjectTemplate> internalFieldObjects;
- };
-
- class V8ScriptEngine : public ScriptEngine {
- public:
- V8ScriptEngine();
- virtual ~V8ScriptEngine();
-
- virtual Scope * createScope() { return new V8Scope( this ); }
-
- virtual void runTest() {}
-
- bool utf8Ok() const { return true; }
-
- class V8UnlockForClient : public Unlocker {
- V8Unlock u_;
- };
-
- virtual auto_ptr<Unlocker> newThreadUnlocker() { return auto_ptr< Unlocker >( new V8UnlockForClient ); }
-
- virtual void interrupt( unsigned opSpec );
- virtual void interruptAll();
-
- private:
- friend class V8Scope;
- };
-
- class ExternalString : public v8::String::ExternalAsciiStringResource {
- public:
- ExternalString(std::string str) : _data(str) {
- }
-
- ~ExternalString() {
- }
-
- const char* data () const { return _data.c_str(); }
- size_t length () const { return _data.length(); }
- private:
-// string _str;
-// const char* _data;
- std::string _data;
-// size_t _len;
- };
-
- extern ScriptEngine * globalScriptEngine;
- extern map< unsigned, int > __interruptSpecToThreadId;
-
-}
diff --git a/scripting/sm_db.cpp b/scripting/sm_db.cpp
deleted file mode 100644
index 2a9169ba082..00000000000
--- a/scripting/sm_db.cpp
+++ /dev/null
@@ -1,1240 +0,0 @@
-// sm_db.cpp
-
-/* 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.
- */
-
-// hacked in right now from engine_spidermonkey.cpp
-
-#include "../client/syncclusterconnection.h"
-#include "../util/base64.h"
-#include "../util/text.h"
-#include "../util/hex.h"
-
-#if( BOOST_VERSION >= 104200 )
-//#include <boost/uuid/uuid.hpp>
-#define HAVE_UUID 1
-#else
-;
-#endif
-
-namespace mongo {
-
- bool haveLocalShardingInfo( const string& ns );
-
- // ------------ some defs needed ---------------
-
- JSObject * doCreateCollection( JSContext * cx , JSObject * db , const string& shortName );
-
- // ------------ utils ------------------
-
-
- bool isSpecialName( const string& name ) {
- static set<string> names;
- if ( names.size() == 0 ) {
- names.insert( "tojson" );
- names.insert( "toJson" );
- names.insert( "toString" );
- }
-
- if ( name.length() == 0 )
- return false;
-
- if ( name[0] == '_' )
- return true;
-
- return names.count( name ) > 0;
- }
-
-
- // ------ cursor ------
-
- class CursorHolder {
- public:
- CursorHolder( auto_ptr< DBClientCursor > &cursor, const shared_ptr< DBClientWithCommands > &connection ) :
- connection_( connection ),
- cursor_( cursor ) {
- assert( cursor_.get() );
- }
- DBClientCursor *get() const { return cursor_.get(); }
- private:
- shared_ptr< DBClientWithCommands > connection_;
- auto_ptr< DBClientCursor > cursor_;
- };
-
- DBClientCursor *getCursor( JSContext *cx, JSObject *obj ) {
- CursorHolder * holder = (CursorHolder*)JS_GetPrivate( cx , obj );
- uassert( 10235 , "no cursor!" , holder );
- return holder->get();
- }
-
- JSBool internal_cursor_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- uassert( 10236 , "no args to internal_cursor_constructor" , argc == 0 );
- assert( JS_SetPrivate( cx , obj , 0 ) ); // just for safety
- return JS_TRUE;
- }
-
- void internal_cursor_finalize( JSContext * cx , JSObject * obj ) {
- CursorHolder * holder = (CursorHolder*)JS_GetPrivate( cx , obj );
- if ( holder ) {
- delete holder;
- assert( JS_SetPrivate( cx , obj , 0 ) );
- }
- }
-
- JSBool internal_cursor_hasNext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- DBClientCursor *cursor = getCursor( cx, obj );
- try {
- *rval = cursor->more() ? JSVAL_TRUE : JSVAL_FALSE;
- }
- catch ( std::exception& e ) {
- JS_ReportError( cx , e.what() );
- return JS_FALSE;
- }
- return JS_TRUE;
- }
-
- JSBool internal_cursor_objsLeftInBatch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- DBClientCursor *cursor = getCursor( cx, obj );
- Convertor c(cx);
- *rval = c.toval((double) cursor->objsLeftInBatch() );
- return JS_TRUE;
- }
-
- JSBool internal_cursor_next(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- DBClientCursor *cursor = getCursor( cx, obj );
-
- BSONObj n;
-
- try {
- if ( ! cursor->more() ) {
- JS_ReportError( cx , "cursor at the end" );
- return JS_FALSE;
- }
-
- n = cursor->next();
- }
- catch ( std::exception& e ) {
- JS_ReportError( cx , e.what() );
- return JS_FALSE;
- }
-
- Convertor c(cx);
- *rval = c.toval( &n );
- return JS_TRUE;
- }
-
- JSFunctionSpec internal_cursor_functions[] = {
- { "hasNext" , internal_cursor_hasNext , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "objsLeftInBatch" , internal_cursor_objsLeftInBatch , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "next" , internal_cursor_next , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { 0 }
- };
-
- JSClass internal_cursor_class = {
- "InternalCursor" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, internal_cursor_finalize,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
-
- // ------ mongo stuff ------
-
- JSBool mongo_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- uassert( 10237 , "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 );
-
- shared_ptr< DBClientWithCommands > client( createDirectClient() );
- assert( JS_SetPrivate( cx , obj , (void*)( new shared_ptr< DBClientWithCommands >( client ) ) ) );
-
- jsval host = c.toval( "EMBEDDED" );
- assert( JS_SetProperty( cx , obj , "host" , &host ) );
-
- return JS_TRUE;
- }
-
- JSBool mongo_external_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
-
- smuassert( cx , "0 or 1 args to Mongo" , argc <= 1 );
-
- string host = "127.0.0.1";
- if ( argc > 0 )
- host = c.toString( argv[0] );
-
- string errmsg;
-
- ConnectionString cs = ConnectionString::parse( host , errmsg );
- if ( ! cs.isValid() ) {
- JS_ReportError( cx , errmsg.c_str() );
- return JS_FALSE;
- }
-
- shared_ptr< DBClientWithCommands > conn( cs.connect( errmsg ) );
- if ( ! conn ) {
- JS_ReportError( cx , errmsg.c_str() );
- return JS_FALSE;
- }
-
- try{
- ScriptEngine::runConnectCallback( *conn );
- }
- catch( std::exception& e ){
- // Can happen if connection goes down while we're starting up here
- // Catch so that we don't get a hard-to-trace segfault from SM
- JS_ReportError( cx, ((string)( str::stream() << "Error during mongo startup." << causedBy( e ) )).c_str() );
- return JS_FALSE;
- }
-
- assert( JS_SetPrivate( cx , obj , (void*)( new shared_ptr< DBClientWithCommands >( conn ) ) ) );
- jsval host_val = c.toval( host.c_str() );
- assert( JS_SetProperty( cx , obj , "host" , &host_val ) );
- return JS_TRUE;
-
- }
-
- DBClientWithCommands *getConnection( JSContext *cx, JSObject *obj ) {
- shared_ptr< DBClientWithCommands > * connHolder = (shared_ptr< DBClientWithCommands >*)JS_GetPrivate( cx , obj );
- uassert( 10239 , "no connection!" , connHolder && connHolder->get() );
- return connHolder->get();
- }
-
- void mongo_finalize( JSContext * cx , JSObject * obj ) {
- shared_ptr< DBClientWithCommands > * connHolder = (shared_ptr< DBClientWithCommands >*)JS_GetPrivate( cx , obj );
- if ( connHolder ) {
- delete connHolder;
- assert( JS_SetPrivate( cx , obj , 0 ) );
- }
- }
-
- 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,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSBool mongo_find(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- smuassert( cx , "mongo_find needs 7 args" , argc == 7 );
- shared_ptr< DBClientWithCommands > * connHolder = (shared_ptr< DBClientWithCommands >*)JS_GetPrivate( cx , obj );
- smuassert( cx , "no connection!" , connHolder && connHolder->get() );
- DBClientWithCommands *conn = connHolder->get();
-
- Convertor c( cx );
-
- string ns = c.toString( argv[0] );
-
- BSONObj q = c.toObject( argv[1] );
- BSONObj f = c.toObject( argv[2] );
-
- int nToReturn = (int) c.toNumber( argv[3] );
- int nToSkip = (int) c.toNumber( argv[4] );
- bool slaveOk = c.getBoolean( obj , "slaveOk" );
- int batchSize = (int) c.toNumber( argv[5] );
- int options = (int)c.toNumber( argv[6] );
-
- try {
-
- auto_ptr<DBClientCursor> cursor = conn->query( ns , q , nToReturn , nToSkip , f.nFields() ? &f : 0 , options | ( slaveOk ? QueryOption_SlaveOk : 0 ) , batchSize );
- if ( ! cursor.get() ) {
- log() << "query failed : " << ns << " " << q << " to: " << conn->toString() << endl;
- JS_ReportError( cx , "error doing query: failed" );
- return JS_FALSE;
- }
- JSObject * mycursor = JS_NewObject( cx , &internal_cursor_class , 0 , 0 );
- CHECKNEWOBJECT( mycursor, cx, "internal_cursor_class" );
- assert( JS_SetPrivate( cx , mycursor , new CursorHolder( cursor, *connHolder ) ) );
- *rval = OBJECT_TO_JSVAL( mycursor );
- return JS_TRUE;
- }
- catch ( ... ) {
- JS_ReportError( cx , "error doing query: unknown" );
- return JS_FALSE;
- }
- }
-
- JSBool mongo_update(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- smuassert( cx , "mongo_find needs at elast 3 args" , argc >= 3 );
- smuassert( cx , "2nd param to update has to be an object" , JSVAL_IS_OBJECT( argv[1] ) );
- smuassert( cx , "3rd param to update has to be an object" , JSVAL_IS_OBJECT( argv[2] ) );
-
- Convertor c( cx );
- if ( c.getBoolean( obj , "readOnly" ) ) {
- JS_ReportError( cx , "js db in read only mode - mongo_update" );
- return JS_FALSE;
- }
-
- DBClientWithCommands * conn = getConnection( cx, obj );
- uassert( 10245 , "no connection!" , conn );
-
- string ns = c.toString( argv[0] );
-
- bool upsert = argc > 3 && c.toBoolean( argv[3] );
- bool multi = argc > 4 && c.toBoolean( argv[4] );
-
- try {
- conn->update( ns , c.toObject( argv[1] ) , c.toObject( argv[2] ) , upsert , multi );
- return JS_TRUE;
- }
- catch ( ... ) {
- JS_ReportError( cx , "error doing update" );
- return JS_FALSE;
- }
- }
-
- JSBool mongo_insert(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- smuassert( cx , "mongo_insert needs 2 args" , argc == 2 );
- smuassert( cx , "2nd param to insert has to be an object" , JSVAL_IS_OBJECT( argv[1] ) );
-
- Convertor c( cx );
- if ( c.getBoolean( obj , "readOnly" ) ) {
- JS_ReportError( cx , "js db in read only mode - mongo_insert" );
- return JS_FALSE;
- }
-
- DBClientWithCommands * conn = getConnection( cx, obj );
- uassert( 10248 , "no connection!" , conn );
-
- string ns = c.toString( argv[0] );
-
- try {
- BSONObj o = c.toObject( argv[1] );
- // TODO: add _id
-
- conn->insert( ns , o );
- return JS_TRUE;
- }
- catch ( std::exception& e ) {
- stringstream ss;
- ss << "error doing insert:" << e.what();
- string s = ss.str();
- JS_ReportError( cx , s.c_str() );
- return JS_FALSE;
- }
- catch ( ... ) {
- JS_ReportError( cx , "error doing insert" );
- return JS_FALSE;
- }
- }
-
- JSBool mongo_remove(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- smuassert( cx , "mongo_remove needs 2 or 3 arguments" , argc == 2 || argc == 3 );
- smuassert( cx , "2nd param to insert has to be an object" , JSVAL_IS_OBJECT( argv[1] ) );
-
- Convertor c( cx );
- if ( c.getBoolean( obj , "readOnly" ) ) {
- JS_ReportError( cx , "js db in read only mode - mongo_remove" );
- return JS_FALSE;
- }
-
- DBClientWithCommands * conn = getConnection( cx, obj );
- uassert( 10251 , "no connection!" , conn );
-
- string ns = c.toString( argv[0] );
- BSONObj o = c.toObject( argv[1] );
- bool justOne = false;
- if ( argc > 2 )
- justOne = c.toBoolean( argv[2] );
-
- try {
- conn->remove( ns , o , justOne );
- return JS_TRUE;
- }
- catch ( std::exception& e ) {
- JS_ReportError( cx , e.what() );
- return JS_FALSE;
- }
-
- catch ( ... ) {
- JS_ReportError( cx , "error doing remove" );
- return JS_FALSE;
- }
-
- }
-
- JSFunctionSpec mongo_functions[] = {
- { "find" , mongo_find , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "update" , mongo_update , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "insert" , mongo_insert , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "remove" , mongo_remove , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { 0 }
- };
-
- // ------------- db_collection -------------
-
- JSBool db_collection_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- smuassert( cx , "db_collection_constructor wrong args" , argc == 4 );
- assert( JS_SetProperty( cx , obj , "_mongo" , &(argv[0]) ) );
- assert( JS_SetProperty( cx , obj , "_db" , &(argv[1]) ) );
- assert( JS_SetProperty( cx , obj , "_shortName" , &(argv[2]) ) );
- assert( JS_SetProperty( cx , obj , "_fullName" , &(argv[3]) ) );
-
- Convertor c(cx);
- if ( haveLocalShardingInfo( c.toString( argv[3] ) ) ) {
- JS_ReportError( cx , "can't use sharded collection from db.eval" );
- return JS_FALSE;
- }
-
- return JS_TRUE;
- }
-
- JSBool db_collection_resolve( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp ) {
- if ( flags & JSRESOLVE_ASSIGNING )
- return JS_TRUE;
-
- Convertor c( cx );
- string collname = c.toString( id );
-
- if ( isSpecialName( collname ) )
- return JS_TRUE;
-
- if ( obj == c.getGlobalPrototype( "DBCollection" ) )
- return JS_TRUE;
-
- JSObject * proto = JS_GetPrototype( cx , obj );
- if ( c.hasProperty( obj , collname.c_str() ) || ( proto && c.hasProperty( proto , collname.c_str() ) ) )
- return JS_TRUE;
-
- string name = c.toString( c.getProperty( obj , "_shortName" ) );
- name += ".";
- name += collname;
-
- jsval db = c.getProperty( obj , "_db" );
- if ( ! JSVAL_IS_OBJECT( db ) )
- return JS_TRUE;
-
- JSObject * coll = doCreateCollection( cx , JSVAL_TO_OBJECT( db ) , name );
- if ( ! coll )
- return JS_FALSE;
- c.setProperty( obj , collname.c_str() , OBJECT_TO_JSVAL( coll ) );
- *objp = obj;
- return JS_TRUE;
- }
-
- JSClass db_collection_class = {
- "DBCollection" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, (JSResolveOp)(&db_collection_resolve) , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
-
- JSObject * doCreateCollection( JSContext * cx , JSObject * db , const string& shortName ) {
- Convertor c(cx);
-
- assert( c.hasProperty( db , "_mongo" ) );
- assert( c.hasProperty( db , "_name" ) );
-
- JSObject * coll = JS_NewObject( cx , &db_collection_class , 0 , 0 );
- CHECKNEWOBJECT( coll, cx, "doCreateCollection" );
- c.setProperty( coll , "_mongo" , c.getProperty( db , "_mongo" ) );
- c.setProperty( coll , "_db" , OBJECT_TO_JSVAL( db ) );
- c.setProperty( coll , "_shortName" , c.toval( shortName.c_str() ) );
-
- string name = c.toString( c.getProperty( db , "_name" ) );
- name += "." + shortName;
- c.setProperty( coll , "_fullName" , c.toval( name.c_str() ) );
-
- if ( haveLocalShardingInfo( name ) ) {
- JS_ReportError( cx , "can't use sharded collection from db.eval" );
- return 0;
- }
-
- return coll;
- }
-
- // -------------- DB ---------------
-
-
- JSBool db_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- smuassert( cx, "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 db_resolve( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp ) {
- if ( flags & JSRESOLVE_ASSIGNING )
- return JS_TRUE;
-
- Convertor c( cx );
-
- if ( obj == c.getGlobalPrototype( "DB" ) )
- return JS_TRUE;
-
- string collname = c.toString( id );
-
- if ( isSpecialName( collname ) )
- return JS_TRUE;
-
- JSObject * proto = JS_GetPrototype( cx , obj );
- if ( proto && c.hasProperty( proto , collname.c_str() ) )
- return JS_TRUE;
-
- JSObject * coll = doCreateCollection( cx , obj , collname );
- if ( ! coll )
- return JS_FALSE;
- c.setProperty( obj , collname.c_str() , OBJECT_TO_JSVAL( coll ) );
-
- *objp = obj;
- return JS_TRUE;
- }
-
- JSClass db_class = {
- "DB" , JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, (JSResolveOp)(&db_resolve) , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
-
- // -------------- object id -------------
-
- JSBool object_id_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
-
- OID oid;
- if ( argc == 0 ) {
- oid.init();
- }
- else {
- smuassert( cx , "object_id_constructor can't take more than 1 param" , argc == 1 );
- string s = c.toString( argv[0] );
-
- try {
- Scope::validateObjectIdString( s );
- }
- catch ( const MsgAssertionException &m ) {
- static string error = m.toString();
- JS_ReportError( cx, error.c_str() );
- return JS_FALSE;
- }
- oid.init( s );
- }
-
- if ( ! JS_InstanceOf( cx , obj , &object_id_class , 0 ) ) {
- obj = JS_NewObject( cx , &object_id_class , 0 , 0 );
- CHECKNEWOBJECT( obj, cx, "object_id_constructor" );
- *rval = OBJECT_TO_JSVAL( obj );
- }
-
- jsval v = c.toval( oid.str().c_str() );
- assert( JS_SetProperty( cx , obj , "str" , &v ) );
-
- return JS_TRUE;
- }
-
- JSClass object_id_class = {
- "ObjectId" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSBool object_id_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- return (JSBool) (*rval = c.getProperty( obj , "str" ));
- }
-
- JSFunctionSpec object_id_functions[] = {
- { "toString" , object_id_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { 0 }
- };
-
- // dbpointer
-
- JSBool dbpointer_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
-
- if ( argc == 2 ) {
-
- if ( ! JSVAL_IS_OID( argv[1] ) ) {
- JS_ReportError( cx , "2nd arg to DBPointer needs to be oid" );
- return JS_FALSE;
- }
-
- assert( JS_SetProperty( cx , obj , "ns" , &(argv[0]) ) );
- assert( JS_SetProperty( cx , obj , "id" , &(argv[1]) ) );
- return JS_TRUE;
- }
- else {
- JS_ReportError( cx , "DBPointer needs 2 arguments" );
- return JS_FALSE;
- }
- }
-
- JSClass dbpointer_class = {
- "DBPointer" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSFunctionSpec dbpointer_functions[] = {
- { 0 }
- };
-
-
- JSBool dbref_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
-
- if ( argc == 2 ) {
- JSObject * o = JS_NewObject( cx , NULL , NULL, NULL );
- CHECKNEWOBJECT( o, cx, "dbref_constructor" );
- assert( JS_SetProperty( cx, o , "$ref" , &argv[ 0 ] ) );
- assert( JS_SetProperty( cx, o , "$id" , &argv[ 1 ] ) );
- BSONObj bo = c.toObject( o );
- assert( JS_SetPrivate( cx , obj , (void*)(new BSONHolder( bo.getOwned() ) ) ) );
- return JS_TRUE;
- }
- else {
- JS_ReportError( cx , "DBRef needs 2 arguments" );
- assert( JS_SetPrivate( cx , obj , (void*)(new BSONHolder( BSONObj().getOwned() ) ) ) );
- return JS_FALSE;
- }
- }
-
- JSClass dbref_class = bson_class; // name will be fixed later
-
- // UUID **************************
-
-#if 0
- JSBool uuid_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
-
- if( argc == 0 ) {
-#if defined(HAVE_UUID)
- //uuids::uuid
-#else
-#endif
- JS_ReportError( cx , "UUID needs 1 argument -- UUID(hexstr)" );
- return JS_FALSE;
- }
- else if ( argc == 1 ) {
-
- string encoded = c.toString( argv[ 0 ] );
- if( encoded.size() != 32 ) {
- JS_ReportError( cx, "expect 32 char hex string to UUID()" );
- return JS_FALSE;
- }
-
- char buf[16];
- for( int i = 0; i < 16; i++ ) {
- buf[i] = fromHex(encoded.c_str() + i * 2);
- }
-
-zzz
-
- assert( JS_SetPrivate( cx, obj, new BinDataHolder( buf, 16 ) ) );
- c.setProperty( obj, "len", c.toval( (double)16 ) );
- c.setProperty( obj, "type", c.toval( (double)3 ) );
-
- return JS_TRUE;
- }
- else {
- JS_ReportError( cx , "UUID needs 1 argument -- UUID(hexstr)" );
- return JS_FALSE;
- }
- }
-
- JSBool uuid_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- void *holder = JS_GetPrivate( cx, obj );
- assert( holder );
- const char *data = ( ( BinDataHolder* )( holder ) )->c_;
- stringstream ss;
- ss << "UUID(\"" << toHex(data, 16);
- ss << "\")";
- string ret = ss.str();
- return *rval = c.toval( ret.c_str() );
- }
-
- void uuid_finalize( JSContext * cx , JSObject * obj ) {
- Convertor c(cx);
- void *holder = JS_GetPrivate( cx, obj );
- if ( holder ) {
- delete ( BinDataHolder* )holder;
- assert( JS_SetPrivate( cx , obj , 0 ) );
- }
- }
-
- JSClass uuid_class = {
- "UUID" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, uuid_finalize,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSFunctionSpec uuid_functions[] = {
- { "toString" , uuid_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { 0 }
- };
-
-#endif
-
- // BinData **************************
-
- JSBool bindata_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- Convertor c( cx );
-
- if ( argc == 2 ) {
-
- int type = (int)c.toNumber( argv[ 0 ] );
- if( type < 0 || type > 255 ) {
- JS_ReportError( cx , "invalid BinData subtype -- range is 0..255 see bsonspec.org" );
- return JS_FALSE;
- }
- string encoded = c.toString( argv[ 1 ] );
- string decoded;
- try {
- decoded = base64::decode( encoded );
- }
- catch(...) {
- JS_ReportError(cx, "BinData could not decode base64 parameter");
- return JS_FALSE;
- }
-
- assert( JS_SetPrivate( cx, obj, new BinDataHolder( decoded.data(), decoded.length() ) ) );
- c.setProperty( obj, "len", c.toval( (double)decoded.length() ) );
- c.setProperty( obj, "type", c.toval( (double)type ) );
-
- return JS_TRUE;
- }
- else {
- JS_ReportError( cx , "BinData needs 2 arguments -- BinData(subtype,data)" );
- return JS_FALSE;
- }
- }
-
- JSBool bindata_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- int type = (int)c.getNumber( obj , "type" );
- int len = (int)c.getNumber( obj, "len" );
- void *holder = JS_GetPrivate( cx, obj );
- assert( holder );
- const char *data = ( ( BinDataHolder* )( holder ) )->c_;
- stringstream ss;
- ss << "BinData(" << type << ",\"";
- base64::encode( ss, (const char *)data, len );
- ss << "\")";
- string ret = ss.str();
- return *rval = c.toval( ret.c_str() );
- }
-
- JSBool bindataBase64(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- int len = (int)c.getNumber( obj, "len" );
- void *holder = JS_GetPrivate( cx, obj );
- assert( holder );
- const char *data = ( ( BinDataHolder* )( holder ) )->c_;
- stringstream ss;
- base64::encode( ss, (const char *)data, len );
- string ret = ss.str();
- return *rval = c.toval( ret.c_str() );
- }
-
- JSBool bindataAsHex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- int len = (int)c.getNumber( obj, "len" );
- void *holder = JS_GetPrivate( cx, obj );
- assert( holder );
- const char *data = ( ( BinDataHolder* )( holder ) )->c_;
- stringstream ss;
- ss.setf (ios_base::hex , ios_base::basefield);
- ss.fill ('0');
- ss.setf (ios_base::right , ios_base::adjustfield);
- for( int i = 0; i < len; i++ ) {
- unsigned v = (unsigned char) data[i];
- ss << setw(2) << v;
- }
- string ret = ss.str();
- return *rval = c.toval( ret.c_str() );
- }
-
- void bindata_finalize( JSContext * cx , JSObject * obj ) {
- Convertor c(cx);
- void *holder = JS_GetPrivate( cx, obj );
- if ( holder ) {
- delete ( BinDataHolder* )holder;
- assert( JS_SetPrivate( cx , obj , 0 ) );
- }
- }
-
- JSClass bindata_class = {
- "BinData" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, bindata_finalize,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSFunctionSpec bindata_functions[] = {
- { "toString" , bindata_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "hex", bindataAsHex, 0, JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "base64", bindataBase64, 0, JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { 0 }
- };
-
- // Map
-
- bool specialMapString( const string& s ) {
- return s == "put" || s == "get" || s == "_get" || s == "values" || s == "_data" || s == "constructor" ;
- }
-
- JSBool map_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- if ( argc > 0 ) {
- JS_ReportError( cx , "Map takes no arguments" );
- return JS_FALSE;
- }
-
- JSObject * array = JS_NewObject( cx , 0 , 0 , 0 );
- CHECKNEWOBJECT( array, cx, "map_constructor" );
-
- jsval a = OBJECT_TO_JSVAL( array );
- JS_SetProperty( cx , obj , "_data" , &a );
-
- return JS_TRUE;
- }
-
- JSBool map_prop( JSContext *cx, JSObject *obj, jsval idval, jsval *vp ) {
- Convertor c(cx);
- if ( specialMapString( c.toString( idval ) ) )
- return JS_TRUE;
-
- log() << "illegal prop access: " << c.toString( idval ) << endl;
- JS_ReportError( cx , "can't use array access with Map" );
- return JS_FALSE;
- }
-
- JSClass map_class = {
- "Map" , JSCLASS_HAS_PRIVATE ,
- map_prop, JS_PropertyStub, map_prop, map_prop,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSFunctionSpec map_functions[] = {
- { 0 }
- };
-
-
- // -----
-
- JSClass timestamp_class = {
- "Timestamp" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSBool timestamp_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- smuassert( cx , "Timestamp needs 0 or 2 args" , argc == 0 || argc == 2 );
-
- if ( ! JS_InstanceOf( cx , obj , &timestamp_class , 0 ) ) {
- obj = JS_NewObject( cx , &timestamp_class , 0 , 0 );
- CHECKNEWOBJECT( obj, cx, "timestamp_constructor" );
- *rval = OBJECT_TO_JSVAL( obj );
- }
-
- Convertor c( cx );
- if ( argc == 0 ) {
- c.setProperty( obj, "t", c.toval( 0.0 ) );
- c.setProperty( obj, "i", c.toval( 0.0 ) );
- }
- else {
- c.setProperty( obj, "t", argv[ 0 ] );
- c.setProperty( obj, "i", argv[ 1 ] );
- }
-
- return JS_TRUE;
- }
-
-
- JSClass numberlong_class = {
- "NumberLong" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSBool numberlong_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- smuassert( cx , "NumberLong needs 0 or 1 args" , argc == 0 || argc == 1 );
-
- if ( ! JS_InstanceOf( cx , obj , &numberlong_class , 0 ) ) {
- obj = JS_NewObject( cx , &numberlong_class , 0 , 0 );
- CHECKNEWOBJECT( obj, cx, "numberlong_constructor" );
- *rval = OBJECT_TO_JSVAL( obj );
- }
-
- Convertor c( cx );
- if ( argc == 0 ) {
- c.setProperty( obj, "floatApprox", c.toval( 0.0 ) );
- }
- else if ( JSVAL_IS_NUMBER( argv[ 0 ] ) ) {
- c.setProperty( obj, "floatApprox", argv[ 0 ] );
- }
- else {
- string num = c.toString( argv[ 0 ] );
- //PRINT(num);
- const char *numStr = num.c_str();
- long long n;
- try {
- n = parseLL( numStr );
- //PRINT(n);
- }
- catch ( const AssertionException & ) {
- smuassert( cx , "could not convert string to long long" , false );
- }
- c.makeLongObj( n, obj );
- }
-
- return JS_TRUE;
- }
-
- JSBool numberlong_valueof(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- return *rval = c.toval( double( c.toNumberLongUnsafe( obj ) ) );
- }
-
- JSBool numberlong_tonumber(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- return numberlong_valueof( cx, obj, argc, argv, rval );
- }
-
- JSBool numberlong_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- stringstream ss;
- long long val = c.toNumberLongUnsafe( obj );
- const long long limit = 2LL << 30;
-
- if ( val <= -limit || limit <= val )
- ss << "NumberLong(\"" << val << "\")";
- else
- ss << "NumberLong(" << val << ")";
-
- string ret = ss.str();
- return *rval = c.toval( ret.c_str() );
- }
-
- JSFunctionSpec numberlong_functions[] = {
- { "valueOf" , numberlong_valueof , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "toNumber" , numberlong_tonumber , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "toString" , numberlong_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { 0 }
- };
-
- JSClass numberint_class = {
- "NumberInt" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSBool numberint_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- smuassert( cx , "NumberInt needs 0 or 1 args" , argc == 0 || argc == 1 );
-
- if ( ! JS_InstanceOf( cx , obj , &numberint_class , 0 ) ) {
- obj = JS_NewObject( cx , &numberint_class , 0 , 0 );
- CHECKNEWOBJECT( obj, cx, "numberint_constructor" );
- *rval = OBJECT_TO_JSVAL( obj );
- }
-
- Convertor c( cx );
- if ( argc == 0 ) {
- c.setProperty( obj, "floatApprox", c.toval( 0.0 ) );
- }
- else if ( JSVAL_IS_NUMBER( argv[ 0 ] ) ) {
- c.setProperty( obj, "floatApprox", argv[ 0 ] );
- }
- else {
- string num = c.toString( argv[ 0 ] );
- //PRINT(num);
- const char *numStr = num.c_str();
- int n;
- try {
- n = (int) parseLL( numStr );
- //PRINT(n);
- }
- catch ( const AssertionException & ) {
- smuassert( cx , "could not convert string to integer" , false );
- }
- c.makeIntObj( n, obj );
- }
-
- return JS_TRUE;
- }
-
- JSBool numberint_valueof(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- return *rval = c.toval( double( c.toNumberInt( obj ) ) );
- }
-
- JSBool numberint_tonumber(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- return numberint_valueof( cx, obj, argc, argv, rval );
- }
-
- JSBool numberint_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- int val = c.toNumberInt( obj );
- string ret = str::stream() << "NumberInt(" << val << ")";
- return *rval = c.toval( ret.c_str() );
- }
-
- JSBool numberint_tojson(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
- Convertor c(cx);
- int val = c.toNumberInt( obj );
- string ret = str::stream() << val;
- return *rval = c.toval( ret.c_str() );
- }
-
-
- JSFunctionSpec numberint_functions[] = {
- { "valueOf" , numberint_valueof , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "toNumber" , numberint_tonumber , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "toString" , numberint_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { "tojson" , numberint_tojson , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
- { 0 }
- };
-
- JSClass minkey_class = {
- "MinKey" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- JSClass maxkey_class = {
- "MaxKey" , JSCLASS_HAS_PRIVATE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- // dbquery
-
- JSBool dbquery_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ) {
- smuassert( cx , "DDQuery needs at least 4 args" , argc >= 4 );
-
- Convertor c(cx);
- c.setProperty( obj , "_mongo" , argv[0] );
- c.setProperty( obj , "_db" , argv[1] );
- c.setProperty( obj , "_collection" , argv[2] );
- c.setProperty( obj , "_ns" , argv[3] );
-
- if ( argc > 4 && JSVAL_IS_OBJECT( argv[4] ) )
- c.setProperty( obj , "_query" , argv[4] );
- else {
- JSObject * temp = JS_NewObject( cx , 0 , 0 , 0 );
- CHECKNEWOBJECT( temp, cx, "dbquery_constructor" );
- c.setProperty( obj , "_query" , OBJECT_TO_JSVAL( temp ) );
- }
-
- if ( argc > 5 && JSVAL_IS_OBJECT( argv[5] ) )
- c.setProperty( obj , "_fields" , argv[5] );
- else
- c.setProperty( obj , "_fields" , JSVAL_NULL );
-
-
- if ( argc > 6 && JSVAL_IS_NUMBER( argv[6] ) )
- c.setProperty( obj , "_limit" , argv[6] );
- else
- c.setProperty( obj , "_limit" , JSVAL_ZERO );
-
- if ( argc > 7 && JSVAL_IS_NUMBER( argv[7] ) )
- c.setProperty( obj , "_skip" , argv[7] );
- else
- c.setProperty( obj , "_skip" , JSVAL_ZERO );
-
- if ( argc > 8 && JSVAL_IS_NUMBER( argv[8] ) )
- c.setProperty( obj , "_batchSize" , argv[8] );
- else
- c.setProperty( obj , "_batchSize" , JSVAL_ZERO );
-
- if ( argc > 9 && JSVAL_IS_NUMBER( argv[9] ) )
- c.setProperty( obj , "_options" , argv[8] );
- else
- c.setProperty( obj , "_options" , JSVAL_ZERO );
-
-
- c.setProperty( obj , "_cursor" , JSVAL_NULL );
- c.setProperty( obj , "_numReturned" , JSVAL_ZERO );
- c.setProperty( obj , "_special" , JSVAL_FALSE );
-
- return JS_TRUE;
- }
-
- JSBool dbquery_resolve( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp ) {
- if ( flags & JSRESOLVE_ASSIGNING )
- return JS_TRUE;
-
- if ( ! JSVAL_IS_NUMBER( id ) )
- return JS_TRUE;
-
- jsval val = JSVAL_VOID;
- assert( JS_CallFunctionName( cx , obj , "arrayAccess" , 1 , &id , &val ) );
- Convertor c(cx);
- c.setProperty( obj , c.toString( id ).c_str() , val );
- *objp = obj;
- return JS_TRUE;
- }
-
- JSClass dbquery_class = {
- "DBQuery" , JSCLASS_NEW_RESOLVE ,
- JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
- JS_EnumerateStub, (JSResolveOp)(&dbquery_resolve) , JS_ConvertStub, JS_FinalizeStub,
- JSCLASS_NO_OPTIONAL_MEMBERS
- };
-
- // ---- other stuff ----
-
- void initMongoJS( SMScope * scope , JSContext * cx , JSObject * global , bool local ) {
-
- assert( JS_InitClass( cx , global , 0 , &mongo_class , local ? mongo_local_constructor : mongo_external_constructor , 0 , 0 , mongo_functions , 0 , 0 ) );
-
- assert( JS_InitClass( cx , global , 0 , &object_id_class , object_id_constructor , 0 , 0 , object_id_functions , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &db_class , db_constructor , 2 , 0 , 0 , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &db_collection_class , db_collection_constructor , 4 , 0 , 0 , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &internal_cursor_class , internal_cursor_constructor , 0 , 0 , internal_cursor_functions , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &dbquery_class , dbquery_constructor , 0 , 0 , 0 , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &dbpointer_class , dbpointer_constructor , 0 , 0 , dbpointer_functions , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &bindata_class , bindata_constructor , 0 , 0 , bindata_functions , 0 , 0 ) );
-// assert( JS_InitClass( cx , global , 0 , &uuid_class , uuid_constructor , 0 , 0 , uuid_functions , 0 , 0 ) );
-
- assert( JS_InitClass( cx , global , 0 , &timestamp_class , timestamp_constructor , 0 , 0 , 0 , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &numberlong_class , numberlong_constructor , 0 , 0 , numberlong_functions , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &numberint_class , numberint_constructor , 0 , 0 , numberint_functions , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &minkey_class , 0 , 0 , 0 , 0 , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &maxkey_class , 0 , 0 , 0 , 0 , 0 , 0 ) );
-
- assert( JS_InitClass( cx , global , 0 , &map_class , map_constructor , 0 , 0 , map_functions , 0 , 0 ) );
-
- assert( JS_InitClass( cx , global , 0 , &bson_ro_class , bson_cons , 0 , 0 , bson_functions , 0 , 0 ) );
- assert( JS_InitClass( cx , global , 0 , &bson_class , bson_cons , 0 , 0 , bson_functions , 0 , 0 ) );
-
- static const char *dbrefName = "DBRef";
- dbref_class.name = dbrefName;
- assert( JS_InitClass( cx , global , 0 , &dbref_class , dbref_constructor , 2 , 0 , bson_functions , 0 , 0 ) );
-
- scope->execCoreFiles();
- }
-
- bool appendSpecialDBObject( Convertor * c , BSONObjBuilder& b , const string& name , jsval val , JSObject * o ) {
-
- if ( JS_InstanceOf( c->_context , o , &object_id_class , 0 ) ) {
- OID oid;
- oid.init( c->getString( o , "str" ) );
- b.append( name , oid );
- return true;
- }
-
- if ( JS_InstanceOf( c->_context , o , &minkey_class , 0 ) ) {
- b.appendMinKey( name );
- return true;
- }
-
- if ( JS_InstanceOf( c->_context , o , &maxkey_class , 0 ) ) {
- b.appendMaxKey( name );
- return true;
- }
-
- if ( JS_InstanceOf( c->_context , o , &timestamp_class , 0 ) ) {
- b.appendTimestamp( name , (unsigned long long)c->getNumber( o , "t" ) , (unsigned int )c->getNumber( o , "i" ) );
- return true;
- }
-
- if ( JS_InstanceOf( c->_context , o , &numberlong_class , 0 ) ) {
- b.append( name , c->toNumberLongUnsafe( o ) );
- return true;
- }
-
- if ( JS_InstanceOf( c->_context , o , &numberint_class , 0 ) ) {
- b.append( name , c->toNumberInt( o ) );
- return true;
- }
-
- if ( JS_InstanceOf( c->_context , o , &dbpointer_class , 0 ) ) {
- b.appendDBRef( name , c->getString( o , "ns" ) , c->toOID( c->getProperty( o , "id" ) ) );
- return true;
- }
-
- if ( JS_InstanceOf( c->_context , o , &bindata_class , 0 ) ) {
- void *holder = JS_GetPrivate( c->_context , o );
- const char *data = ( ( BinDataHolder * )( holder ) )->c_;
- b.appendBinData( name ,
- (int)(c->getNumber( o , "len" )) , (BinDataType)((char)(c->getNumber( o , "type" ) ) ) ,
- data
- );
- return true;
- }
-
-#if defined( SM16 ) || defined( MOZJS )
-#warning dates do not work in your version of spider monkey
- {
- jsdouble d = js_DateGetMsecSinceEpoch( c->_context , o );
- if ( d ) {
- b.appendDate( name , Date_t(d) );
- return true;
- }
- }
-#elif defined( XULRUNNER )
- if ( JS_InstanceOf( c->_context , o, globalSMEngine->_dateClass , 0 ) ) {
- jsdouble d = js_DateGetMsecSinceEpoch( c->_context , o );
- b.appendDate( name , Date_t(d) );
- return true;
- }
-#else
- if ( JS_InstanceOf( c->_context , o, &js_DateClass , 0 ) ) {
- jsdouble d = js_DateGetMsecSinceEpoch( c->_context , o );
- long long d2 = (long long)d;
- b.appendDate( name , Date_t((unsigned long long)d2) );
- return true;
- }
-#endif
-
-
- if ( JS_InstanceOf( c->_context , o , &dbquery_class , 0 ) ||
- JS_InstanceOf( c->_context , o , &mongo_class , 0 ) ||
- JS_InstanceOf( c->_context , o , &db_collection_class , 0 ) ) {
- b.append( name , c->toString( val ) );
- return true;
- }
-
-#if defined( XULRUNNER )
- if ( JS_InstanceOf( c->_context , o , globalSMEngine->_regexClass , 0 ) ) {
- c->appendRegex( b , name , c->toString( val ) );
- return true;
- }
-#elif defined( SM18 )
- if ( JS_InstanceOf( c->_context , o , &js_RegExpClass , 0 ) ) {
- c->appendRegex( b , name , c->toString( val ) );
- return true;
- }
-#endif
-
- return false;
- }
-
- bool isDate( JSContext * cx , JSObject * o ) {
-#if defined( SM16 ) || defined( MOZJS ) || defined( XULRUNNER )
- return js_DateGetMsecSinceEpoch( cx , o ) != 0;
-#else
- return JS_InstanceOf( cx , o, &js_DateClass, 0 );
-#endif
- }
-
-}
diff --git a/scripting/utils.cpp b/scripting/utils.cpp
deleted file mode 100644
index 612b173fdf8..00000000000
--- a/scripting/utils.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-// utils.cpp
-/*
- * Copyright (C) 2010 10gen Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "pch.h"
-#include "engine.h"
-#include "../util/md5.hpp"
-#include "../util/version.h"
-
-namespace mongo {
-
- void installBenchmarkSystem( Scope& scope );
-
- BSONObj jsmd5( const BSONObj &a, void* data ) {
- uassert( 10261 , "js md5 needs a string" , a.firstElement().type() == String );
- const char * s = a.firstElement().valuestrsafe();
-
- md5digest d;
- md5_state_t st;
- md5_init(&st);
- md5_append( &st , (const md5_byte_t*)s , strlen( s ) );
- md5_finish(&st, d);
-
- return BSON( "" << digestToString( d ) );
- }
-
- BSONObj JSVersion( const BSONObj& args, void* data ) {
- cout << "version: " << versionString << endl;
- if ( strstr( versionString , "+" ) )
- printGitVersion();
- return BSONObj();
- }
-
-
- BSONObj JSSleep(const mongo::BSONObj &args, void* data) {
- assert( args.nFields() == 1 );
- assert( args.firstElement().isNumber() );
- int ms = int( args.firstElement().number() );
- {
- auto_ptr< ScriptEngine::Unlocker > u = globalScriptEngine->newThreadUnlocker();
- sleepmillis( ms );
- }
-
- BSONObjBuilder b;
- b.appendUndefined( "" );
- return b.obj();
- }
-
- // ---------------------------------
- // ---- installer --------
- // ---------------------------------
-
- void installGlobalUtils( Scope& scope ) {
- scope.injectNative( "hex_md5" , jsmd5 );
- scope.injectNative( "version" , JSVersion );
- scope.injectNative( "sleep" , JSSleep );
-
- installBenchmarkSystem( scope );
- }
-
-}
-
-
diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp
deleted file mode 100644
index f2f53338763..00000000000
--- a/scripting/v8_db.cpp
+++ /dev/null
@@ -1,1049 +0,0 @@
-// v8_db.cpp
-
-/* 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.
- */
-
-#if defined(_WIN32)
-/** this is a hack - v8stdint.h defined uint16_t etc. on _WIN32 only, and that collides with
- our usage of boost */
-#include "boost/cstdint.hpp"
-using namespace boost;
-#define V8STDINT_H_
-#endif
-
-#include "v8_wrapper.h"
-#include "v8_utils.h"
-#include "engine_v8.h"
-#include "v8_db.h"
-#include "util/base64.h"
-#include "util/text.h"
-#include "../client/syncclusterconnection.h"
-#include "../s/d_logic.h"
-#include <iostream>
-
-using namespace std;
-using namespace v8;
-
-namespace mongo {
-
-#define DDD(x)
-
- v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( V8Scope* scope, bool local ) {
- v8::Handle<v8::FunctionTemplate> mongo;
- if ( local ) {
- mongo = scope->createV8Function(mongoConsLocal);
- }
- else {
- mongo = scope->createV8Function(mongoConsExternal);
- }
- mongo->InstanceTemplate()->SetInternalFieldCount( 1 );
- v8::Handle<v8::Template> proto = mongo->PrototypeTemplate();
- scope->injectV8Function("find", mongoFind, proto);
- scope->injectV8Function("insert", mongoInsert, proto);
- scope->injectV8Function("remove", mongoRemove, proto);
- scope->injectV8Function("update", mongoUpdate, proto);
-
- v8::Handle<FunctionTemplate> ic = scope->createV8Function(internalCursorCons);
- ic->InstanceTemplate()->SetInternalFieldCount( 1 );
- v8::Handle<v8::Template> icproto = ic->PrototypeTemplate();
- scope->injectV8Function("next", internalCursorNext, icproto);
- scope->injectV8Function("hasNext", internalCursorHasNext, icproto);
- scope->injectV8Function("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto);
- proto->Set( scope->getV8Str( "internalCursor" ) , ic );
-
- return mongo;
- }
-
- v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> numberLong = scope->createV8Function(numberLongInit);
- v8::Local<v8::Template> proto = numberLong->PrototypeTemplate();
- scope->injectV8Function("valueOf", numberLongValueOf, proto);
- scope->injectV8Function("toNumber", numberLongToNumber, proto);
- scope->injectV8Function("toString", numberLongToString, proto);
-
- return numberLong;
- }
-
- v8::Handle<v8::FunctionTemplate> getNumberIntFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> numberInt = scope->createV8Function(numberIntInit);
- v8::Local<v8::Template> proto = numberInt->PrototypeTemplate();
- scope->injectV8Function("valueOf", numberIntValueOf, proto);
- scope->injectV8Function("toNumber", numberIntToNumber, proto);
- scope->injectV8Function("toString", numberIntToString, proto);
-
- return numberInt;
- }
-
- v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> binData = scope->createV8Function(binDataInit);
- binData->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Local<v8::Template> proto = binData->PrototypeTemplate();
- scope->injectV8Function("toString", binDataToString, proto);
- scope->injectV8Function("base64", binDataToBase64, proto);
- scope->injectV8Function("hex", binDataToHex, proto);
- return binData;
- }
-
- v8::Handle<v8::FunctionTemplate> getUUIDFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(uuidInit);
- templ->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Local<v8::Template> proto = templ->PrototypeTemplate();
- scope->injectV8Function("toString", binDataToString, proto);
- scope->injectV8Function("base64", binDataToBase64, proto);
- scope->injectV8Function("hex", binDataToHex, proto);
- return templ;
- }
-
- v8::Handle<v8::FunctionTemplate> getMD5FunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(md5Init);
- templ->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Local<v8::Template> proto = templ->PrototypeTemplate();
- scope->injectV8Function("toString", binDataToString, proto);
- scope->injectV8Function("base64", binDataToBase64, proto);
- scope->injectV8Function("hex", binDataToHex, proto);
- return templ;
- }
-
- v8::Handle<v8::FunctionTemplate> getHexDataFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(hexDataInit);
- templ->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Local<v8::Template> proto = templ->PrototypeTemplate();
- scope->injectV8Function("toString", binDataToString, proto);
- scope->injectV8Function("base64", binDataToBase64, proto);
- scope->injectV8Function("hex", binDataToHex, proto);
- return templ;
- }
-
- v8::Handle<v8::FunctionTemplate> getTimestampFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> ts = scope->createV8Function(dbTimestampInit);
- /* v8::Local<v8::Template> proto = */ ts->PrototypeTemplate();
- ts->InstanceTemplate()->SetInternalFieldCount( 1 );
-
- return ts;
- }
-
-// void installDBTypes( V8Scope* scope, Handle<ObjectTemplate>& global ) {
-// v8::Handle<v8::FunctionTemplate> db = scope->createV8Function(dbInit);
-// db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
-// global->Set(v8::String::New("DB") , db );
-//
-// v8::Handle<v8::FunctionTemplate> dbCollection = scope->createV8Function(collectionInit);
-// dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
-// global->Set(v8::String::New("DBCollection") , dbCollection );
-//
-//
-// v8::Handle<v8::FunctionTemplate> dbQuery = scope->createV8Function(dbQueryInit);
-// dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess );
-// global->Set(v8::String::New("DBQuery") , dbQuery );
-//
-// global->Set( v8::String::New("ObjectId") , newV8Function< objectIdInit >(scope) );
-//
-// global->Set( v8::String::New("DBRef") , newV8Function< dbRefInit >(scope) );
-//
-// global->Set( v8::String::New("DBPointer") , newV8Function< dbPointerInit >(scope) );
-//
-// global->Set( v8::String::New("BinData") , getBinDataFunctionTemplate(scope) );
-//
-// global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate(scope) );
-//
-// global->Set( v8::String::New("Timestamp") , getTimestampFunctionTemplate(scope) );
-// }
-
- void installDBTypes( V8Scope* scope, v8::Handle<v8::Object>& global ) {
- v8::Handle<v8::FunctionTemplate> db = scope->createV8Function(dbInit);
- db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
- global->Set(scope->getV8Str("DB") , db->GetFunction() );
- v8::Handle<v8::FunctionTemplate> dbCollection = scope->createV8Function(collectionInit);
- dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
- global->Set(scope->getV8Str("DBCollection") , dbCollection->GetFunction() );
-
-
- v8::Handle<v8::FunctionTemplate> dbQuery = scope->createV8Function(dbQueryInit);
- dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess );
- global->Set(scope->getV8Str("DBQuery") , dbQuery->GetFunction() );
-
- scope->injectV8Function("ObjectId", objectIdInit, global);
- scope->injectV8Function("DBRef", dbRefInit, global);
- scope->injectV8Function("DBPointer", dbPointerInit, global);
-
- global->Set( scope->getV8Str("BinData") , getBinDataFunctionTemplate(scope)->GetFunction() );
- global->Set( scope->getV8Str("UUID") , getUUIDFunctionTemplate(scope)->GetFunction() );
- global->Set( scope->getV8Str("MD5") , getMD5FunctionTemplate(scope)->GetFunction() );
- global->Set( scope->getV8Str("HexData") , getHexDataFunctionTemplate(scope)->GetFunction() );
- global->Set( scope->getV8Str("NumberLong") , getNumberLongFunctionTemplate(scope)->GetFunction() );
- global->Set( scope->getV8Str("NumberInt") , getNumberIntFunctionTemplate(scope)->GetFunction() );
- global->Set( scope->getV8Str("Timestamp") , getTimestampFunctionTemplate(scope)->GetFunction() );
-
- BSONObjBuilder b;
- b.appendMaxKey( "" );
- b.appendMinKey( "" );
- BSONObj o = b.obj();
- BSONObjIterator i( o );
- global->Set( scope->getV8Str("MaxKey"), scope->mongoToV8Element( i.next() ) );
- global->Set( scope->getV8Str("MinKey"), scope->mongoToV8Element( i.next() ) );
-
- global->Get( scope->getV8Str( "Object" ) )->ToObject()->Set( scope->getV8Str("bsonsize") , scope->createV8Function(bsonsize)->GetFunction() );
- }
-
- void destroyConnection( Persistent<Value> self, void* parameter) {
- delete static_cast<DBClientBase*>(parameter);
- self.Dispose();
- self.Clear();
- }
-
- Handle<Value> mongoConsExternal(V8Scope* scope, const Arguments& args) {
-
- char host[255];
-
- if ( args.Length() > 0 && args[0]->IsString() ) {
- assert( args[0]->ToString()->Utf8Length() < 250 );
- args[0]->ToString()->WriteAscii( host );
- }
- else {
- strcpy( host , "127.0.0.1" );
- }
-
- string errmsg;
- ConnectionString cs = ConnectionString::parse( host , errmsg );
- if ( ! cs.isValid() )
- return v8::ThrowException( v8::String::New( errmsg.c_str() ) );
-
-
- DBClientWithCommands * conn;
- {
- V8Unlock ul;
- conn = cs.connect( errmsg );
- }
- if ( ! conn )
- return v8::ThrowException( v8::String::New( errmsg.c_str() ) );
-
- Persistent<v8::Object> self = Persistent<v8::Object>::New( args.Holder() );
- self.MakeWeak( conn , destroyConnection );
-
- {
- V8Unlock ul;
- ScriptEngine::runConnectCallback( *conn );
- }
-
- args.This()->SetInternalField( 0 , External::New( conn ) );
- args.This()->Set( scope->getV8Str( "slaveOk" ) , Boolean::New( false ) );
- args.This()->Set( scope->getV8Str( "host" ) , scope->getV8Str( host ) );
-
- return v8::Undefined();
- }
-
- Handle<Value> mongoConsLocal(V8Scope* scope, const Arguments& args) {
-
- if ( args.Length() > 0 )
- return v8::ThrowException( v8::String::New( "local Mongo constructor takes no args" ) );
-
- DBClientBase * conn;
- {
- V8Unlock ul;
- conn = createDirectClient();
- }
-
- Persistent<v8::Object> self = Persistent<v8::Object>::New( args.This() );
- self.MakeWeak( conn , destroyConnection );
-
- // NOTE I don't believe the conn object will ever be freed.
- args.This()->SetInternalField( 0 , External::New( conn ) );
- args.This()->Set( scope->getV8Str( "slaveOk" ) , Boolean::New( false ) );
- args.This()->Set( scope->getV8Str( "host" ) , scope->getV8Str( "EMBEDDED" ) );
-
- return v8::Undefined();
- }
-
-
- // ---
-
-#ifdef _WIN32
-#define GETNS char * ns = new char[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns );
-#else
-#define GETNS char ns[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns );
-#endif
-
- DBClientBase * getConnection( const Arguments& args ) {
- Local<External> c = External::Cast( *(args.This()->GetInternalField( 0 )) );
- DBClientBase * conn = (DBClientBase*)(c->Value());
- assert( conn );
- return conn;
- }
-
- // ---- real methods
-
- void destroyCursor( Persistent<Value> self, void* parameter) {
- delete static_cast<mongo::DBClientCursor*>(parameter);
- self.Dispose();
- self.Clear();
- }
-
- /**
- 0 - namespace
- 1 - query
- 2 - fields
- 3 - limit
- 4 - skip
- */
- Handle<Value> mongoFind(V8Scope* scope, const Arguments& args) {
- HandleScope handle_scope;
-
- jsassert( args.Length() == 7 , "find needs 7 args" );
- jsassert( args[1]->IsObject() , "needs to be an object" );
- DBClientBase * conn = getConnection( args );
- GETNS;
-
- BSONObj q = scope->v8ToMongo( args[1]->ToObject() );
- DDD( "query:" << q );
-
- BSONObj fields;
- bool haveFields = args[2]->IsObject() && args[2]->ToObject()->GetPropertyNames()->Length() > 0;
- if ( haveFields )
- fields = scope->v8ToMongo( args[2]->ToObject() );
-
- Local<v8::Object> mongo = args.This();
- Local<v8::Value> slaveOkVal = mongo->Get( scope->getV8Str( "slaveOk" ) );
- jsassert( slaveOkVal->IsBoolean(), "slaveOk member invalid" );
- bool slaveOk = slaveOkVal->BooleanValue();
-
- try {
- auto_ptr<mongo::DBClientCursor> cursor;
- int nToReturn = (int)(args[3]->ToNumber()->Value());
- int nToSkip = (int)(args[4]->ToNumber()->Value());
- int batchSize = (int)(args[5]->ToNumber()->Value());
- int options = (int)(args[6]->ToNumber()->Value());
- {
- V8Unlock u;
- cursor = conn->query( ns, q , nToReturn , nToSkip , haveFields ? &fields : 0, options | ( slaveOk ? QueryOption_SlaveOk : 0 ) , batchSize );
- if ( ! cursor.get() )
- return v8::ThrowException( v8::String::New( "error doing query: failed" ) );
- }
- v8::Function * cons = (v8::Function*)( *( mongo->Get( scope->getV8Str( "internalCursor" ) ) ) );
- assert( cons );
-
- Persistent<v8::Object> c = Persistent<v8::Object>::New( cons->NewInstance() );
- c.MakeWeak( cursor.get() , destroyCursor );
-
- c->SetInternalField( 0 , External::New( cursor.release() ) );
- return handle_scope.Close(c);
- }
- catch ( ... ) {
- return v8::ThrowException( v8::String::New( "socket error on query" ) );
- }
- }
-
- v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args) {
- jsassert( args.Length() == 2 , "insert needs 2 args" );
- jsassert( args[1]->IsObject() , "have to insert an object" );
-
- if ( args.This()->Get( scope->getV8Str( "readOnly" ) )->BooleanValue() )
- return v8::ThrowException( v8::String::New( "js db in read only mode" ) );
-
- DBClientBase * conn = getConnection( args );
- GETNS;
-
- v8::Handle<v8::Object> in = args[1]->ToObject();
-
- if ( ! in->Has( scope->getV8Str( "_id" ) ) ) {
- v8::Handle<v8::Value> argv[1];
- in->Set( scope->getV8Str( "_id" ) , scope->getObjectIdCons()->NewInstance( 0 , argv ) );
- }
-
- BSONObj o = scope->v8ToMongo( in );
-
- DDD( "want to save : " << o.jsonString() );
- try {
- V8Unlock u;
- conn->insert( ns , o );
- }
- catch ( ... ) {
- return v8::ThrowException( v8::String::New( "socket error on insert" ) );
- }
-
- return v8::Undefined();
- }
-
- v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args) {
- jsassert( args.Length() == 2 || args.Length() == 3 , "remove needs 2 args" );
- jsassert( args[1]->IsObject() , "have to remove an object template" );
-
- if ( args.This()->Get( scope->getV8Str( "readOnly" ) )->BooleanValue() )
- return v8::ThrowException( v8::String::New( "js db in read only mode" ) );
-
- DBClientBase * conn = getConnection( args );
- GETNS;
-
- v8::Handle<v8::Object> in = args[1]->ToObject();
- BSONObj o = scope->v8ToMongo( in );
-
- bool justOne = false;
- if ( args.Length() > 2 ) {
- justOne = args[2]->BooleanValue();
- }
-
- DDD( "want to remove : " << o.jsonString() );
- try {
- V8Unlock u;
- conn->remove( ns , o , justOne );
- }
- catch ( ... ) {
- return v8::ThrowException( v8::String::New( "socket error on remove" ) );
- }
-
- return v8::Undefined();
- }
-
- v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args) {
- jsassert( args.Length() >= 3 , "update needs at least 3 args" );
- jsassert( args[1]->IsObject() , "1st param to update has to be an object" );
- jsassert( args[2]->IsObject() , "2nd param to update has to be an object" );
-
- if ( args.This()->Get( scope->getV8Str( "readOnly" ) )->BooleanValue() )
- return v8::ThrowException( v8::String::New( "js db in read only mode" ) );
-
- DBClientBase * conn = getConnection( args );
- GETNS;
-
- v8::Handle<v8::Object> q = args[1]->ToObject();
- v8::Handle<v8::Object> o = args[2]->ToObject();
-
- bool upsert = args.Length() > 3 && args[3]->IsBoolean() && args[3]->ToBoolean()->Value();
- bool multi = args.Length() > 4 && args[4]->IsBoolean() && args[4]->ToBoolean()->Value();
-
- try {
- BSONObj q1 = scope->v8ToMongo( q );
- BSONObj o1 = scope->v8ToMongo( o );
- V8Unlock u;
- conn->update( ns , q1 , o1 , upsert, multi );
- }
- catch ( ... ) {
- return v8::ThrowException( v8::String::New( "socket error on remove" ) );
- }
-
- return v8::Undefined();
- }
-
-
-
-
- // --- cursor ---
-
- mongo::DBClientCursor * getCursor( const Arguments& args ) {
- Local<External> c = External::Cast( *(args.This()->GetInternalField( 0 ) ) );
-
- mongo::DBClientCursor * cursor = (mongo::DBClientCursor*)(c->Value());
- return cursor;
- }
-
- v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Arguments& args) {
- return v8::Undefined();
- }
-
- v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Arguments& args) {
- mongo::DBClientCursor * cursor = getCursor( args );
- if ( ! cursor )
- return v8::Undefined();
- BSONObj o;
- {
- V8Unlock u;
- o = cursor->next();
- }
- bool ro = false;
- if (args.This()->Has(scope->V8STR_RO))
- ro = args.This()->Get(scope->V8STR_RO)->BooleanValue();
- return scope->mongoToLZV8( o, false, ro );
- }
-
- v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args) {
- mongo::DBClientCursor * cursor = getCursor( args );
- if ( ! cursor )
- return Boolean::New( false );
- bool ret;
- {
- V8Unlock u;
- ret = cursor->more();
- }
- return Boolean::New( ret );
- }
-
- v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, const v8::Arguments& args) {
- mongo::DBClientCursor * cursor = getCursor( args );
- if ( ! cursor )
- return v8::Number::New( (double) 0 );
- int ret;
- {
- V8Unlock u;
- ret = cursor->objsLeftInBatch();
- }
- return v8::Number::New( (double) ret );
- }
-
-// v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8::Arguments& args) {
-// Local<v8::Object> cursor = args.This();
-// cursor->Set(scope->V8STR_RO, v8::Undefined());
-// return cursor;
-// }
-
- // --- DB ----
-
- v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) {
- assert( args.Length() == 2 );
-
- args.This()->Set( scope->getV8Str( "_mongo" ) , args[0] );
- args.This()->Set( scope->getV8Str( "_name" ) , args[1] );
-
- for ( int i=0; i<args.Length(); i++ )
- assert( ! args[i]->IsUndefined() );
-
- return v8::Undefined();
- }
-
- v8::Handle<v8::Value> collectionInit( V8Scope* scope, const v8::Arguments& args ) {
- assert( args.Length() == 4 );
-
- args.This()->Set( scope->getV8Str( "_mongo" ) , args[0] );
- args.This()->Set( scope->getV8Str( "_db" ) , args[1] );
- args.This()->Set( scope->getV8Str( "_shortName" ) , args[2] );
- args.This()->Set( scope->getV8Str( "_fullName" ) , args[3] );
-
- if ( haveLocalShardingInfo( toSTLString( args[3] ) ) )
- return v8::ThrowException( v8::String::New( "can't use sharded collection from db.eval" ) );
-
- for ( int i=0; i<args.Length(); i++ )
- assert( ! args[i]->IsUndefined() );
-
- return v8::Undefined();
- }
-
- v8::Handle<v8::Value> dbQueryInit( V8Scope* scope, const v8::Arguments& args ) {
-
- v8::Handle<v8::Object> t = args.This();
-
- assert( args.Length() >= 4 );
-
- t->Set( scope->getV8Str( "_mongo" ) , args[0] );
- t->Set( scope->getV8Str( "_db" ) , args[1] );
- t->Set( scope->getV8Str( "_collection" ) , args[2] );
- t->Set( scope->getV8Str( "_ns" ) , args[3] );
-
- if ( args.Length() > 4 && args[4]->IsObject() )
- t->Set( scope->getV8Str( "_query" ) , args[4] );
- else
- t->Set( scope->getV8Str( "_query" ) , v8::Object::New() );
-
- if ( args.Length() > 5 && args[5]->IsObject() )
- t->Set( scope->getV8Str( "_fields" ) , args[5] );
- else
- t->Set( scope->getV8Str( "_fields" ) , v8::Null() );
-
-
- if ( args.Length() > 6 && args[6]->IsNumber() )
- t->Set( scope->getV8Str( "_limit" ) , args[6] );
- else
- t->Set( scope->getV8Str( "_limit" ) , Number::New( 0 ) );
-
- if ( args.Length() > 7 && args[7]->IsNumber() )
- t->Set( scope->getV8Str( "_skip" ) , args[7] );
- else
- t->Set( scope->getV8Str( "_skip" ) , Number::New( 0 ) );
-
- if ( args.Length() > 8 && args[8]->IsNumber() )
- t->Set( scope->getV8Str( "_batchSize" ) , args[8] );
- else
- t->Set( scope->getV8Str( "_batchSize" ) , Number::New( 0 ) );
-
- if ( args.Length() > 9 && args[9]->IsNumber() )
- t->Set( scope->getV8Str( "_options" ) , args[9] );
- else
- t->Set( scope->getV8Str( "_options" ) , Number::New( 0 ) );
-
-
- t->Set( scope->getV8Str( "_cursor" ) , v8::Null() );
- t->Set( scope->getV8Str( "_numReturned" ) , v8::Number::New(0) );
- t->Set( scope->getV8Str( "_special" ) , Boolean::New(false) );
-
- return v8::Undefined();
- }
-
- v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, const v8::AccessorInfo &info) {
- DDD( "collectionFallback [" << name << "]" );
-
- v8::Handle<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get( name );
- if ( ! real->IsUndefined() )
- return real;
-
- string sname = toSTLString( name );
- if ( sname[0] == '_' ) {
- if ( ! ( info.This()->HasRealNamedProperty( name ) ) )
- return v8::Undefined();
- return info.This()->GetRealNamedPropertyInPrototypeChain( name );
- }
-
- v8::Handle<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get( v8::String::New( "getCollection" ) );
- assert( getCollection->IsFunction() );
-
- v8::Function * f = (v8::Function*)(*getCollection);
- v8::Handle<v8::Value> argv[1];
- argv[0] = name;
-
- return f->Call( info.This() , 1 , argv );
- }
-
- v8::Handle<v8::Value> dbQueryIndexAccess( unsigned int index , const v8::AccessorInfo& info ) {
- v8::Handle<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get( v8::String::New( "arrayAccess" ) );
- assert( arrayAccess->IsFunction() );
-
- v8::Function * f = (v8::Function*)(*arrayAccess);
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::Number::New( index );
-
- return f->Call( info.This() , 1 , argv );
- }
-
- v8::Handle<v8::Value> objectIdInit( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
- v8::Function * f = scope->getObjectIdCons();
- it = f->NewInstance();
- }
-
- OID oid;
-
- if ( args.Length() == 0 ) {
- oid.init();
- }
- else {
- string s = toSTLString( args[0] );
- try {
- Scope::validateObjectIdString( s );
- }
- catch ( const MsgAssertionException &m ) {
- string error = m.toString();
- return v8::ThrowException( v8::String::New( error.c_str() ) );
- }
- oid.init( s );
- }
-
- it->Set( scope->getV8Str( "str" ) , v8::String::New( oid.str().c_str() ) );
-
- return it;
- }
-
- v8::Handle<v8::Value> dbRefInit( V8Scope* scope, const v8::Arguments& args ) {
-
- if (args.Length() != 2 && args.Length() != 0) {
- return v8::ThrowException( v8::String::New( "DBRef needs 2 arguments" ) );
- }
-
- v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
- v8::Function* f = scope->getNamedCons( "DBRef" );
- it = f->NewInstance();
- }
-
- if ( args.Length() == 2 ) {
- it->Set( scope->getV8Str( "$ref" ) , args[0] );
- it->Set( scope->getV8Str( "$id" ) , args[1] );
- }
-
- return it;
- }
-
- v8::Handle<v8::Value> dbPointerInit( V8Scope* scope, const v8::Arguments& args ) {
-
- if (args.Length() != 2) {
- return v8::ThrowException( v8::String::New( "DBPointer needs 2 arguments" ) );
- }
-
- v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
- v8::Function* f = scope->getNamedCons( "DBPointer" );
- it = f->NewInstance();
- }
-
- it->Set( scope->getV8Str( "ns" ) , args[0] );
- it->Set( scope->getV8Str( "id" ) , args[1] );
- it->SetHiddenValue( scope->getV8Str( "__DBPointer" ), v8::Number::New( 1 ) );
-
- return it;
- }
-
- v8::Handle<v8::Value> dbTimestampInit( V8Scope* scope, const v8::Arguments& args ) {
-
- v8::Handle<v8::Object> it = args.This();
-
- if ( args.Length() == 0 ) {
- it->Set( scope->getV8Str( "t" ) , v8::Number::New( 0 ) );
- it->Set( scope->getV8Str( "i" ) , v8::Number::New( 0 ) );
- }
- else if ( args.Length() == 2 ) {
- it->Set( scope->getV8Str( "t" ) , args[0] );
- it->Set( scope->getV8Str( "i" ) , args[1] );
- }
- else {
- return v8::ThrowException( v8::String::New( "Timestamp needs 0 or 2 arguments" ) );
- }
-
- it->SetInternalField( 0, v8::Uint32::New( Timestamp ) );
-
- return it;
- }
-
-
- v8::Handle<v8::Value> binDataInit( V8Scope* scope, const v8::Arguments& args ) {
- v8::Local<v8::Object> it = args.This();
-
- Handle<Value> type;
- Handle<Value> len;
- int rlen;
- char* data;
- if (args.Length() == 3) {
- // 3 args: len, type, data
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
- v8::Function* f = scope->getNamedCons( "BinData" );
- it = f->NewInstance();
- }
-
- len = args[0];
- rlen = len->IntegerValue();
- type = args[1];
- v8::String::Utf8Value utf( args[ 2 ] );
- char* tmp = *utf;
- data = new char[rlen];
- memcpy(data, tmp, rlen);
- }
- else if ( args.Length() == 2 ) {
- // 2 args: type, base64 string
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
- v8::Function* f = scope->getNamedCons( "BinData" );
- it = f->NewInstance();
- }
-
- type = args[0];
- v8::String::Utf8Value utf( args[ 1 ] );
- string decoded = base64::decode( *utf );
- const char* tmp = decoded.data();
- rlen = decoded.length();
- data = new char[rlen];
- memcpy(data, tmp, rlen);
- len = v8::Number::New(rlen);
-// it->Set( scope->getV8Str( "data" ), v8::String::New( decoded.data(), decoded.length() ) );
- }
- else {
- return v8::ThrowException( v8::String::New( "BinData needs 2 or 3 arguments" ) );
- }
-
- it->Set( scope->getV8Str( "len" ) , len );
- it->Set( scope->getV8Str( "type" ) , type );
- it->SetHiddenValue( scope->V8STR_BINDATA, v8::Number::New( 1 ) );
- Persistent<v8::Object> res = scope->wrapArrayObject(it, data);
- return res;
- }
-
- v8::Handle<v8::Value> binDataToString( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
- int len = it->Get( scope->V8STR_LEN )->Int32Value();
- int type = it->Get( scope->V8STR_TYPE )->Int32Value();
- Local<External> c = External::Cast( *(it->GetInternalField( 0 )) );
- char* data = (char*)(c->Value());
-
- stringstream ss;
- ss << "BinData(" << type << ",\"";
- base64::encode( ss, data, len );
- ss << "\")";
- string ret = ss.str();
- return v8::String::New( ret.c_str() );
- }
-
- v8::Handle<v8::Value> binDataToBase64( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
- int len = Handle<v8::Number>::Cast(it->Get(scope->V8STR_LEN))->Int32Value();
- Local<External> c = External::Cast( *(it->GetInternalField( 0 )) );
- char* data = (char*)(c->Value());
- stringstream ss;
- base64::encode( ss, (const char *)data, len );
- return v8::String::New(ss.str().c_str());
- }
-
- v8::Handle<v8::Value> binDataToHex( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
- int len = Handle<v8::Number>::Cast(it->Get(scope->V8STR_LEN))->Int32Value();
- Local<External> c = External::Cast( *(it->GetInternalField( 0 )) );
- char* data = (char*)(c->Value());
- stringstream ss;
- ss.setf (ios_base::hex , ios_base::basefield);
- ss.fill ('0');
- ss.setf (ios_base::right , ios_base::adjustfield);
- for( int i = 0; i < len; i++ ) {
- unsigned v = (unsigned char) data[i];
- ss << setw(2) << v;
- }
- return v8::String::New(ss.str().c_str());
- }
-
- static v8::Handle<v8::Value> hexToBinData( V8Scope* scope, v8::Local<v8::Object> it, int type, string hexstr ) {
- int len = hexstr.length() / 2;
- char* data = new char[len];
- const char* src = hexstr.c_str();
- for( int i = 0; i < 16; i++ ) {
- data[i] = fromHex(src + i * 2);
- }
-
- it->Set( scope->V8STR_LEN , v8::Number::New(len) );
- it->Set( scope->V8STR_TYPE , v8::Number::New(type) );
- it->SetHiddenValue( scope->V8STR_BINDATA, v8::Number::New( 1 ) );
- Persistent<v8::Object> res = scope->wrapArrayObject(it, data);
- return res;
- }
-
- v8::Handle<v8::Value> uuidInit( V8Scope* scope, const v8::Arguments& args ) {
- if (args.Length() != 1) {
- return v8::ThrowException( v8::String::New( "UUIS needs 1 argument" ) );
- }
- v8::String::Utf8Value utf( args[ 0 ] );
- if( utf.length() != 32 ) {
- return v8::ThrowException( v8::String::New( "UUIS string must have 32 characters" ) );
- }
-
- return hexToBinData(scope, args.This(), bdtUUID, *utf);
- }
-
-// v8::Handle<v8::Value> uuidToString( V8Scope* scope, const v8::Arguments& args ) {
-// v8::Handle<v8::Object> it = args.This();
-// Local<External> c = External::Cast( *(it->GetInternalField( 0 )) );
-// char* data = (char*)(c->Value());
-//
-// stringstream ss;
-// ss << "UUID(\"" << toHex(data, 16) << "\")";
-// return v8::String::New( ss.str().c_str() );
-// }
-
- v8::Handle<v8::Value> md5Init( V8Scope* scope, const v8::Arguments& args ) {
- if (args.Length() != 1) {
- return v8::ThrowException( v8::String::New( "MD5 needs 1 argument" ) );
- }
- v8::String::Utf8Value utf( args[ 0 ] );
- if( utf.length() != 32 ) {
- return v8::ThrowException( v8::String::New( "MD5 string must have 32 characters" ) );
- }
-
- return hexToBinData(scope, args.This(), MD5Type, *utf);
- }
-
- v8::Handle<v8::Value> hexDataInit( V8Scope* scope, const v8::Arguments& args ) {
- if (args.Length() != 2) {
- return v8::ThrowException( v8::String::New( "HexData needs 2 arguments" ) );
- }
- v8::String::Utf8Value utf( args[ 1 ] );
- return hexToBinData(scope, args.This(), args[0]->IntegerValue(), *utf);
- }
-
- v8::Handle<v8::Value> numberLongInit( V8Scope* scope, const v8::Arguments& args ) {
-
- if (args.Length() != 0 && args.Length() != 1 && args.Length() != 3) {
- return v8::ThrowException( v8::String::New( "NumberLong needs 0, 1 or 3 arguments" ) );
- }
-
- v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
- v8::Function* f = scope->getNamedCons( "NumberLong" );
- it = f->NewInstance();
- }
-
- if ( args.Length() == 0 ) {
- it->Set( scope->getV8Str( "floatApprox" ), v8::Number::New( 0 ) );
- }
- else if ( args.Length() == 1 ) {
- if ( args[ 0 ]->IsNumber() ) {
- it->Set( scope->getV8Str( "floatApprox" ), args[ 0 ] );
- }
- else {
- v8::String::Utf8Value data( args[ 0 ] );
- string num = *data;
- const char *numStr = num.c_str();
- long long n;
- try {
- n = parseLL( numStr );
- }
- catch ( const AssertionException & ) {
- return v8::ThrowException( v8::String::New( "could not convert string to long long" ) );
- }
- unsigned long long val = n;
- if ( (long long)val == (long long)(double)(long long)(val) ) {
- it->Set( scope->getV8Str( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) );
- }
- else {
- it->Set( scope->getV8Str( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) );
- it->Set( scope->getV8Str( "top" ), v8::Integer::New( val >> 32 ) );
- it->Set( scope->getV8Str( "bottom" ), v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) ) );
- }
- }
- }
- else {
- it->Set( scope->getV8Str( "floatApprox" ) , args[0] );
- it->Set( scope->getV8Str( "top" ) , args[1] );
- it->Set( scope->getV8Str( "bottom" ) , args[2] );
- }
- it->SetHiddenValue( scope->V8STR_NUMBERLONG, v8::Number::New( 1 ) );
-
- return it;
- }
-
- long long numberLongVal( const v8::Handle< v8::Object > &it ) {
- if ( !it->Has( v8::String::New( "top" ) ) )
- return (long long)( it->Get( v8::String::New( "floatApprox" ) )->NumberValue() );
- return
- (long long)
- ( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
- (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() );
- }
-
- v8::Handle<v8::Value> numberLongValueOf( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
- long long val = numberLongVal( it );
- return v8::Number::New( double( val ) );
- }
-
- v8::Handle<v8::Value> numberLongToNumber( V8Scope* scope, const v8::Arguments& args ) {
- return numberLongValueOf( scope, args );
- }
-
- v8::Handle<v8::Value> numberLongToString( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
-
- stringstream ss;
- long long val = numberLongVal( it );
- const long long limit = 2LL << 30;
-
- if ( val <= -limit || limit <= val )
- ss << "NumberLong(\"" << val << "\")";
- else
- ss << "NumberLong(" << val << ")";
-
- string ret = ss.str();
- return v8::String::New( ret.c_str() );
- }
-
- v8::Handle<v8::Value> numberIntInit( V8Scope* scope, const v8::Arguments& args ) {
-
- if (args.Length() != 0 && args.Length() != 1) {
- return v8::ThrowException( v8::String::New( "NumberInt needs 0, 1 argument" ) );
- }
-
- v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
- v8::Function* f = scope->getNamedCons( "NumberInt" );
- it = f->NewInstance();
- }
-
- if ( args.Length() == 0 ) {
- it->SetHiddenValue( scope->V8STR_NUMBERINT, v8::Number::New( 0 ) );
- }
- else if ( args.Length() == 1 ) {
- it->SetHiddenValue( scope->V8STR_NUMBERINT, args[0]->ToInt32() );
- }
-
- return it;
- }
-
- v8::Handle<v8::Value> numberIntValueOf( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
- int val = it->GetHiddenValue( scope->V8STR_NUMBERINT )->Int32Value();
- return v8::Number::New( double( val ) );
- }
-
- v8::Handle<v8::Value> numberIntToNumber( V8Scope* scope, const v8::Arguments& args ) {
- return numberIntValueOf( scope, args );
- }
-
- v8::Handle<v8::Value> numberIntToString( V8Scope* scope, const v8::Arguments& args ) {
- v8::Handle<v8::Object> it = args.This();
-
- stringstream ss;
- int val = it->GetHiddenValue( scope->V8STR_NUMBERINT )->Int32Value();
- ss << "NumberInt(" << val << ")";
-
- string ret = ss.str();
- return v8::String::New( ret.c_str() );
- }
-
- v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& args ) {
-
- if ( args.Length() != 1 )
- return v8::ThrowException( v8::String::New( "bsonsize needs 1 argument" ) );
-
- if ( args[0]->IsNull() )
- return v8::Number::New(0);
-
- if ( ! args[ 0 ]->IsObject() )
- return v8::ThrowException( v8::String::New( "argument to bsonsize has to be an object" ) );
-
- return v8::Number::New( scope->v8ToMongo( args[ 0 ]->ToObject() ).objsize() );
- }
-
- // to be called with v8 mutex
- void enableV8Interrupt() {
- if ( globalScriptEngine->haveGetInterruptSpecCallback() ) {
- __interruptSpecToThreadId[ globalScriptEngine->getInterruptSpec() ] = v8::V8::GetCurrentThreadId();
- }
- }
-
- // to be called with v8 mutex
- void disableV8Interrupt() {
- if ( globalScriptEngine->haveGetInterruptSpecCallback() ) {
- __interruptSpecToThreadId.erase( globalScriptEngine->getInterruptSpec() );
- }
- }
-
- namespace v8Locks {
- boost::mutex& __v8Mutex = *( new boost::mutex );
- ThreadLocalValue< bool > __locked;
-
- RecursiveLock::RecursiveLock() : _unlock() {
- if ( !__locked.get() ) {
- __v8Mutex.lock();
- __locked.set( true );
- _unlock = true;
- }
- }
- RecursiveLock::~RecursiveLock() {
- if ( _unlock ) {
- __v8Mutex.unlock();
- __locked.set( false );
- }
- }
-
- RecursiveUnlock::RecursiveUnlock() : _lock() {
- if ( __locked.get() ) {
- __v8Mutex.unlock();
- __locked.set( false );
- _lock = true;
- }
- }
- RecursiveUnlock::~RecursiveUnlock() {
- if ( _lock ) {
- __v8Mutex.lock();
- __locked.set( true );
- }
- }
- } // namespace v8Locks
-}
diff --git a/scripting/v8_db.h b/scripting/v8_db.h
deleted file mode 100644
index 08d15d02906..00000000000
--- a/scripting/v8_db.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// v8_db.h
-
-/* 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.
- */
-
-#pragma once
-
-#include <v8.h>
-#include <cstring>
-#include <cstdio>
-#include <cstdlib>
-
-#include "engine_v8.h"
-#include "../client/dbclient.h"
-
-namespace mongo {
-
- // These functions may depend on the caller creating a handle scope and context scope.
-
- v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( V8Scope * scope, bool local );
-// void installDBTypes( V8Scope * scope, v8::Handle<v8::ObjectTemplate>& global );
- void installDBTypes( V8Scope * scope, v8::Handle<v8::Object>& global );
-
- // the actual globals
-
- mongo::DBClientBase * getConnection( const v8::Arguments& args );
-
- // Mongo members
- v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Arguments& args);
-
- v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args);
-
-
- v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, const v8::Arguments& args);
-
- // DB members
-
- v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> objectIdInit( V8Scope* scope, const v8::Arguments& args );
-
- v8::Handle<v8::Value> dbRefInit( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> dbPointerInit( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> dbTimestampInit( V8Scope* scope, const v8::Arguments& args );
-
- v8::Handle<v8::Value> binDataInit( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> binDataToString( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> binDataToBase64( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> binDataToHex( V8Scope* scope, const v8::Arguments& args );
-
- v8::Handle<v8::Value> uuidInit( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> md5Init( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> hexDataInit( V8Scope* scope, const v8::Arguments& args );
-
- v8::Handle<v8::Value> numberLongInit( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Arguments& args);
-
- v8::Handle<v8::Value> numberIntInit( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Arguments& args);
- v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Arguments& args);
-
- v8::Handle<v8::Value> dbQueryInit( V8Scope* scope, const v8::Arguments& args );
- v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::AccessorInfo& info );
-
- v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, const v8::AccessorInfo &info);
-
- v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& args );
-
- // call with v8 mutex:
- void enableV8Interrupt();
- void disableV8Interrupt();
-
-}
-
diff --git a/scripting/v8_utils.cpp b/scripting/v8_utils.cpp
deleted file mode 100644
index 0f575cf31a3..00000000000
--- a/scripting/v8_utils.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-// v8_utils.cpp
-
-/* 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.
- */
-
-#if defined(_WIN32)
-/** this is a hack - v8stdint.h defined uint16_t etc. on _WIN32 only, and that collides with
- our usage of boost */
-#include "boost/cstdint.hpp"
-using namespace boost;
-#define V8STDINT_H_
-#endif
-
-#include "v8_utils.h"
-#include "v8_db.h"
-#include <iostream>
-#include <map>
-#include <sstream>
-#include <vector>
-#include <boost/smart_ptr.hpp>
-#include <boost/thread/thread.hpp>
-#include <boost/thread/xtime.hpp>
-#include "engine_v8.h"
-
-using namespace std;
-using namespace v8;
-
-namespace mongo {
-
- std::string toSTLString( const Handle<v8::Value> & o ) {
- v8::String::Utf8Value str(o);
- const char * foo = *str;
- std::string s(foo);
- return s;
- }
-
- std::string toSTLString( const v8::TryCatch * try_catch ) {
-
- stringstream ss;
-
- //while ( try_catch ){ // disabled for v8 bleeding edge
-
- v8::String::Utf8Value exception(try_catch->Exception());
- Handle<v8::Message> message = try_catch->Message();
-
- if (message.IsEmpty()) {
- ss << *exception << endl;
- }
- else {
-
- v8::String::Utf8Value filename(message->GetScriptResourceName());
- int linenum = message->GetLineNumber();
- ss << *filename << ":" << linenum << " " << *exception << endl;
-
- v8::String::Utf8Value sourceline(message->GetSourceLine());
- ss << *sourceline << endl;
-
- int start = message->GetStartColumn();
- for (int i = 0; i < start; i++)
- ss << " ";
-
- int end = message->GetEndColumn();
- for (int i = start; i < end; i++)
- ss << "^";
-
- ss << endl;
- }
-
- //try_catch = try_catch->next_;
- //}
-
- return ss.str();
- }
-
-
- std::ostream& operator<<( std::ostream &s, const Handle<v8::Value> & o ) {
- v8::String::Utf8Value str(o);
- s << *str;
- return s;
- }
-
- std::ostream& operator<<( std::ostream &s, const v8::TryCatch * try_catch ) {
- HandleScope handle_scope;
- v8::String::Utf8Value exception(try_catch->Exception());
- Handle<v8::Message> message = try_catch->Message();
-
- if (message.IsEmpty()) {
- s << *exception << endl;
- }
- else {
-
- v8::String::Utf8Value filename(message->GetScriptResourceName());
- int linenum = message->GetLineNumber();
- cout << *filename << ":" << linenum << " " << *exception << endl;
-
- v8::String::Utf8Value sourceline(message->GetSourceLine());
- cout << *sourceline << endl;
-
- int start = message->GetStartColumn();
- for (int i = 0; i < start; i++)
- cout << " ";
-
- int end = message->GetEndColumn();
- for (int i = start; i < end; i++)
- cout << "^";
-
- cout << endl;
- }
-
- //if ( try_catch->next_ ) // disabled for v8 bleeding edge
- // s << try_catch->next_;
-
- return s;
- }
-
- void ReportException(v8::TryCatch* try_catch) {
- cout << try_catch << endl;
- }
-
- Handle< Context > baseContext_;
-
- class JSThreadConfig {
- public:
- JSThreadConfig( const Arguments &args, bool newScope = false ) : started_(), done_(), newScope_( newScope ) {
- jsassert( args.Length() > 0, "need at least one argument" );
- jsassert( args[ 0 ]->IsFunction(), "first argument must be a function" );
- Local< v8::Function > f = v8::Function::Cast( *args[ 0 ] );
- f_ = Persistent< v8::Function >::New( f );
- for( int i = 1; i < args.Length(); ++i )
- args_.push_back( Persistent< Value >::New( args[ i ] ) );
- }
- ~JSThreadConfig() {
- f_.Dispose();
- for( vector< Persistent< Value > >::iterator i = args_.begin(); i != args_.end(); ++i )
- i->Dispose();
- returnData_.Dispose();
- }
- void start() {
- jsassert( !started_, "Thread already started" );
- JSThread jt( *this );
- thread_.reset( new boost::thread( jt ) );
- started_ = true;
- }
- void join() {
- jsassert( started_ && !done_, "Thread not running" );
- V8Unlock u;
- thread_->join();
- done_ = true;
- }
- Local< Value > returnData() {
- if ( !done_ )
- join();
- return Local< Value >::New( returnData_ );
- }
- private:
- class JSThread {
- public:
- JSThread( JSThreadConfig &config ) : config_( config ) {}
- void operator()() {
- V8Lock 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 );
- }
- private:
- JSThreadConfig &config_;
- };
-
- bool started_;
- bool done_;
- bool newScope_;
- Persistent< v8::Function > f_;
- vector< Persistent< Value > > args_;
- auto_ptr< boost::thread > thread_;
- Persistent< Value > returnData_;
- };
-
- Handle< Value > ThreadInit( V8Scope* scope, const Arguments &args ) {
- Handle<v8::Object> it = args.This();
- // NOTE I believe the passed JSThreadConfig will never be freed. If this
- // policy is changed, JSThread may no longer be able to store JSThreadConfig
- // by reference.
- it->SetHiddenValue( v8::String::New( "_JSThreadConfig" ), External::New( new JSThreadConfig( args ) ) );
- return v8::Undefined();
- }
-
- Handle< Value > ScopedThreadInit( V8Scope* scope, const Arguments &args ) {
- Handle<v8::Object> it = args.This();
- // NOTE I believe the passed JSThreadConfig will never be freed. If this
- // policy is changed, JSThread may no longer be able to store JSThreadConfig
- // by reference.
- it->SetHiddenValue( v8::String::New( "_JSThreadConfig" ), External::New( new JSThreadConfig( args, true ) ) );
- return v8::Undefined();
- }
-
- JSThreadConfig *thisConfig( V8Scope* scope, const Arguments &args ) {
- Local< External > c = External::Cast( *(args.This()->GetHiddenValue( v8::String::New( "_JSThreadConfig" ) ) ) );
- JSThreadConfig *config = (JSThreadConfig *)( c->Value() );
- return config;
- }
-
- Handle< Value > ThreadStart( V8Scope* scope, const Arguments &args ) {
- thisConfig( scope, args )->start();
- return v8::Undefined();
- }
-
- Handle< Value > ThreadJoin( V8Scope* scope, const Arguments &args ) {
- thisConfig( scope, args )->join();
- return v8::Undefined();
- }
-
- Handle< Value > ThreadReturnData( V8Scope* scope, const Arguments &args ) {
- HandleScope handle_scope;
- return handle_scope.Close( thisConfig( scope, args )->returnData() );
- }
-
- Handle< Value > ThreadInject( V8Scope* scope, const Arguments &args ) {
- jsassert( args.Length() == 1 , "threadInject takes exactly 1 argument" );
- jsassert( args[0]->IsObject() , "threadInject needs to be passed a prototype" );
-
- Local<v8::Object> o = args[0]->ToObject();
-
- scope->injectV8Function("init", ThreadInit, o);
- scope->injectV8Function("start", ThreadStart, o);
- scope->injectV8Function("join", ThreadJoin, o);
- scope->injectV8Function("returnData", ThreadReturnData, o);
-
- return v8::Undefined();
- }
-
- Handle< Value > ScopedThreadInject( V8Scope* scope, const Arguments &args ) {
- jsassert( args.Length() == 1 , "threadInject takes exactly 1 argument" );
- jsassert( args[0]->IsObject() , "threadInject needs to be passed a prototype" );
-
- Local<v8::Object> o = args[0]->ToObject();
-
- scope->injectV8Function("init", ScopedThreadInit, o);
- // inheritance takes care of other member functions
-
- return v8::Undefined();
- }
-
- void installFork( V8Scope* scope, v8::Handle< v8::Object > &global, v8::Handle< v8::Context > &context ) {
- if ( baseContext_.IsEmpty() ) // if this is the shell, first call will be with shell context, otherwise don't expect to use fork() anyway
- baseContext_ = context;
- scope->injectV8Function("_threadInject", ThreadInject, global);
- scope->injectV8Function("_scopedThreadInject", ScopedThreadInject, global);
- }
-
-}
diff --git a/scripting/v8_utils.h b/scripting/v8_utils.h
deleted file mode 100644
index ca5d317885f..00000000000
--- a/scripting/v8_utils.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// v8_utils.h
-
-/* 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.
- */
-
-#pragma once
-
-#include <v8.h>
-
-#include <cstring>
-#include <cstdio>
-#include <cstdlib>
-#include <assert.h>
-#include <iostream>
-
-namespace mongo {
-
- void ReportException(v8::TryCatch* handler);
-
-#define jsassert(x,msg) assert(x)
-
- std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o );
- std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatch> * try_catch );
-
- std::string toSTLString( const v8::Handle<v8::Value> & o );
- std::string toSTLString( const v8::TryCatch * try_catch );
-
- class V8Scope;
- void installFork( V8Scope* scope, v8::Handle< v8::Object > &global, v8::Handle< v8::Context > &context );
-}
-
diff --git a/scripting/v8_wrapper.cpp b/scripting/v8_wrapper.cpp
deleted file mode 100644
index 7c28a39cceb..00000000000
--- a/scripting/v8_wrapper.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-// v8_wrapper.cpp
-
-/* 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.
- */
-
-#if defined(_WIN32)
-/** this is a hack - v8stdint.h defined uint16_t etc. on _WIN32 only, and that collides with
- our usage of boost */
-#include "boost/cstdint.hpp"
-using namespace boost;
-#define V8STDINT_H_
-#endif
-
-#include "v8_wrapper.h"
-#include "v8_utils.h"
-#include "v8_db.h"
-#include "engine_v8.h"
-
-#include <iostream>
-
-using namespace std;
-using namespace v8;
-
-namespace mongo {
-
-#define DDD(x)
-
- // --- object wrapper ---
-
- class WrapperHolder {
- public:
- WrapperHolder( V8Scope* scope, const BSONObj * o , bool readOnly , bool iDelete )
- : _scope(scope), _o(o), _readOnly( readOnly ), _iDelete( iDelete ) {
- }
-
- ~WrapperHolder() {
- if ( _o && _iDelete ) {
- delete _o;
- }
- _o = 0;
- }
-
- 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);
- }
-
- V8Scope* _scope;
- const BSONObj * _o;
- bool _readOnly;
- bool _iDelete;
- };
-
- WrapperHolder * createWrapperHolder( V8Scope* scope, const BSONObj * o , bool readOnly , bool iDelete ) {
- return new WrapperHolder( scope, o , readOnly , iDelete );
- }
-
- WrapperHolder * getWrapper( v8::Handle<v8::Object> o ) {
- Handle<v8::Value> t = o->GetRealNamedProperty( v8::String::New( "_wrapper" ) );
- assert( t->IsExternal() );
- Local<External> c = External::Cast( *t );
- WrapperHolder * w = (WrapperHolder*)(c->Value());
- assert( w );
- return w;
- }
-
-
- Handle<Value> wrapperCons(V8Scope* scope, const Arguments& args) {
- if ( ! ( args.Length() == 1 && args[0]->IsExternal() ) )
- return v8::ThrowException( v8::String::New( "wrapperCons needs 1 External arg" ) );
-
- args.This()->Set( v8::String::New( "_wrapper" ) , args[0] );
-
- return v8::Undefined();
- }
-
- v8::Handle<v8::Value> wrapperGetHandler( v8::Local<v8::String> name, const v8::AccessorInfo &info) {
- return getWrapper( info.This() )->get( name );
- }
-
- v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> t = scope->createV8Function(wrapperCons);
- t->InstanceTemplate()->SetNamedPropertyHandler( wrapperGetHandler );
- return t;
- }
-}
diff --git a/scripting/v8_wrapper.h b/scripting/v8_wrapper.h
deleted file mode 100644
index 22f14e6ae94..00000000000
--- a/scripting/v8_wrapper.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// v8_wrapper.h
-
-/* 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.
- */
-
-#pragma once
-
-#include <v8.h>
-#include <cstring>
-#include <cstdio>
-#include <cstdlib>
-#include "../db/jsobj.h"
-#include "engine_v8.h"
-
-namespace mongo {
-
- v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate(V8Scope* scope);
-
- class WrapperHolder;
- WrapperHolder * createWrapperHolder( V8Scope* scope, const BSONObj * o , bool readOnly , bool iDelete );
-
-}