diff options
Diffstat (limited to 'src/mongo/scripting/v8_utils.cpp')
-rw-r--r-- | src/mongo/scripting/v8_utils.cpp | 613 |
1 files changed, 302 insertions, 311 deletions
diff --git a/src/mongo/scripting/v8_utils.cpp b/src/mongo/scripting/v8_utils.cpp index 42c33c40f65..e37b1fc1e1c 100644 --- a/src/mongo/scripting/v8_utils.cpp +++ b/src/mongo/scripting/v8_utils.cpp @@ -50,366 +50,357 @@ using std::unique_ptr; namespace mongo { - std::string toSTLString(const v8::Handle<v8::Value>& o) { - return StringData(V8String(o)).toString(); - } +std::string toSTLString(const v8::Handle<v8::Value>& o) { + return StringData(V8String(o)).toString(); +} - /** Get the properties of an object (and its prototype) as a comma-delimited string */ - std::string v8ObjectToString(const v8::Handle<v8::Object>& o) { - v8::Local<v8::Array> properties = o->GetPropertyNames(); - v8::String::Utf8Value str(properties); - massert(16696 , "error converting js type to Utf8Value", *str); - return std::string(*str, str.length()); - } +/** Get the properties of an object (and its prototype) as a comma-delimited string */ +std::string v8ObjectToString(const v8::Handle<v8::Object>& o) { + v8::Local<v8::Array> properties = o->GetPropertyNames(); + v8::String::Utf8Value str(properties); + massert(16696, "error converting js type to Utf8Value", *str); + return std::string(*str, str.length()); +} - std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::Value>& o) { - v8::String::Utf8Value str(o); - s << *str; - return s; - } +std::ostream& operator<<(std::ostream& s, const v8::Handle<v8::Value>& o) { + v8::String::Utf8Value str(o); + s << *str; + return s; +} - std::ostream& operator<<(std::ostream& s, const v8::TryCatch* try_catch) { - v8::HandleScope handle_scope; - v8::String::Utf8Value exceptionText(try_catch->Exception()); - v8::Handle<v8::Message> message = try_catch->Message(); +std::ostream& operator<<(std::ostream& s, const v8::TryCatch* try_catch) { + v8::HandleScope handle_scope; + v8::String::Utf8Value exceptionText(try_catch->Exception()); + v8::Handle<v8::Message> message = try_catch->Message(); - if (message.IsEmpty()) { - s << *exceptionText << endl; - } - else { - v8::String::Utf8Value filename(message->GetScriptResourceName()); - int linenum = message->GetLineNumber(); - cout << *filename << ":" << linenum << " " << *exceptionText << endl; + if (message.IsEmpty()) { + s << *exceptionText << endl; + } else { + v8::String::Utf8Value filename(message->GetScriptResourceName()); + int linenum = message->GetLineNumber(); + cout << *filename << ":" << linenum << " " << *exceptionText << endl; - v8::String::Utf8Value sourceline(message->GetSourceLine()); - cout << *sourceline << endl; + v8::String::Utf8Value sourceline(message->GetSourceLine()); + cout << *sourceline << endl; - int start = message->GetStartColumn(); - for (int i = 0; i < start; i++) - cout << " "; + int start = message->GetStartColumn(); + for (int i = 0; i < start; i++) + cout << " "; - int end = message->GetEndColumn(); - for (int i = start; i < end; i++) - cout << "^"; + int end = message->GetEndColumn(); + for (int i = start; i < end; i++) + cout << "^"; - cout << endl; - } - return s; + cout << endl; } + return s; +} - class JSThreadConfig { - public: - JSThreadConfig(V8Scope* scope, const v8::Arguments& args) : - _started(), - _done(), - _sharedData(new SharedData()) { - jsassert(args.Length() > 0, "need at least one argument"); - jsassert(args[0]->IsFunction(), "first argument must be a function"); - - // arguments need to be copied into the isolate, go through bson - BSONObjBuilder b; - for(int i = 0; i < args.Length(); ++i) { - scope->v8ToMongoElement(b, "arg" + BSONObjBuilder::numStr(i), args[i]); - } - _sharedData->_args = b.obj(); +class JSThreadConfig { +public: + JSThreadConfig(V8Scope* scope, const v8::Arguments& args) + : _started(), _done(), _sharedData(new SharedData()) { + jsassert(args.Length() > 0, "need at least one argument"); + jsassert(args[0]->IsFunction(), "first argument must be a function"); + + // arguments need to be copied into the isolate, go through bson + BSONObjBuilder b; + for (int i = 0; i < args.Length(); ++i) { + scope->v8ToMongoElement(b, "arg" + BSONObjBuilder::numStr(i), args[i]); } + _sharedData->_args = b.obj(); + } - ~JSThreadConfig() { - } + ~JSThreadConfig() {} - void start() { - jsassert(!_started, "Thread already started"); - JSThread jt(*this); - _thread.reset(new stdx::thread(jt)); - _started = true; - } - void join() { - jsassert(_started && !_done, "Thread not running"); - _thread->join(); - _done = true; - } + void start() { + jsassert(!_started, "Thread already started"); + JSThread jt(*this); + _thread.reset(new stdx::thread(jt)); + _started = true; + } + void join() { + jsassert(_started && !_done, "Thread not running"); + _thread->join(); + _done = true; + } - /** - * Returns true if the JSThread terminated as a result of an error - * during its execution, and false otherwise. This operation does - * not block, nor does it require join() to have been called. - */ - bool hasFailed() const { - jsassert(_started, "Thread not started"); - return _sharedData->getErrored(); - } + /** + * Returns true if the JSThread terminated as a result of an error + * during its execution, and false otherwise. This operation does + * not block, nor does it require join() to have been called. + */ + bool hasFailed() const { + jsassert(_started, "Thread not started"); + return _sharedData->getErrored(); + } + + BSONObj returnData() { + if (!_done) + join(); + return _sharedData->_returnData; + } - BSONObj returnData() { - if (!_done) - join(); - return _sharedData->_returnData; +private: + /* + * JSThreadConfig doesn't always outlive its JSThread (for example, if the parent thread + * garbage collects the JSThreadConfig before the JSThread has finished running), so any + * data shared between them has to go in a shared_ptr. + */ + class SharedData { + public: + SharedData() : _errored(false) {} + BSONObj _args; + BSONObj _returnData; + void setErrored(bool value) { + stdx::lock_guard<stdx::mutex> lck(_erroredMutex); + _errored = value; + } + bool getErrored() { + stdx::lock_guard<stdx::mutex> lck(_erroredMutex); + return _errored; } private: - /* - * JSThreadConfig doesn't always outlive its JSThread (for example, if the parent thread - * garbage collects the JSThreadConfig before the JSThread has finished running), so any - * data shared between them has to go in a shared_ptr. - */ - class SharedData { - public: - SharedData() : _errored(false) {} - BSONObj _args; - BSONObj _returnData; - void setErrored(bool value) { - stdx::lock_guard<stdx::mutex> lck(_erroredMutex); - _errored = value; - } - bool getErrored() { - stdx::lock_guard<stdx::mutex> lck(_erroredMutex); - return _errored; - } - private: - stdx::mutex _erroredMutex; - bool _errored; - }; - - class JSThread { - public: - JSThread(JSThreadConfig& config) : _sharedData(config._sharedData) {} - - void operator()() { - try { - unique_ptr<V8Scope> scope( - static_cast<V8Scope*>(globalScriptEngine->newScope())); - v8::Locker v8lock(scope->getIsolate()); - v8::Isolate::Scope iscope(scope->getIsolate()); - v8::HandleScope handle_scope; - v8::Context::Scope context_scope(scope->getContext()); - - BSONObj args = _sharedData->_args; - v8::Local<v8::Function> f = v8::Function::Cast( - *(scope->mongoToV8Element(args.firstElement(), true))); - int argc = args.nFields() - 1; - - // TODO SERVER-8016: properly allocate handles on the stack - v8::Local<v8::Value> argv[24]; - BSONObjIterator it(args); + stdx::mutex _erroredMutex; + bool _errored; + }; + + class JSThread { + public: + JSThread(JSThreadConfig& config) : _sharedData(config._sharedData) {} + + void operator()() { + try { + unique_ptr<V8Scope> scope(static_cast<V8Scope*>(globalScriptEngine->newScope())); + v8::Locker v8lock(scope->getIsolate()); + v8::Isolate::Scope iscope(scope->getIsolate()); + v8::HandleScope handle_scope; + v8::Context::Scope context_scope(scope->getContext()); + + BSONObj args = _sharedData->_args; + v8::Local<v8::Function> f = + v8::Function::Cast(*(scope->mongoToV8Element(args.firstElement(), true))); + int argc = args.nFields() - 1; + + // TODO SERVER-8016: properly allocate handles on the stack + v8::Local<v8::Value> argv[24]; + BSONObjIterator it(args); + it.next(); + for (int i = 0; i < argc && i < 24; ++i) { + argv[i] = v8::Local<v8::Value>::New(scope->mongoToV8Element(*it, true)); it.next(); - for(int i = 0; i < argc && i < 24; ++i) { - argv[i] = v8::Local<v8::Value>::New( - scope->mongoToV8Element(*it, true)); - it.next(); - } - v8::TryCatch try_catch; - v8::Handle<v8::Value> ret = - f->Call(scope->getContext()->Global(), argc, argv); - if (ret.IsEmpty() || try_catch.HasCaught()) { - string e = scope->v8ExceptionToSTLString(&try_catch); - log() << "js thread raised js exception: " << e << endl; - ret = v8::Undefined(); - _sharedData->setErrored(true); - } - // ret is translated to BSON to switch isolate - BSONObjBuilder b; - scope->v8ToMongoElement(b, "ret", ret); - _sharedData->_returnData = b.obj(); - } - catch (const DBException& e) { - // Keeping behavior the same as for js exceptions. - log() << "js thread threw c++ exception: " << e.toString(); - _sharedData->setErrored(true); - _sharedData->_returnData = BSON("ret" << BSONUndefined); - } - catch (const std::exception& e) { - log() << "js thread threw c++ exception: " << e.what(); - _sharedData->setErrored(true); - _sharedData->_returnData = BSON("ret" << BSONUndefined); } - catch (...) { - log() << "js thread threw c++ non-exception"; + v8::TryCatch try_catch; + v8::Handle<v8::Value> ret = f->Call(scope->getContext()->Global(), argc, argv); + if (ret.IsEmpty() || try_catch.HasCaught()) { + string e = scope->v8ExceptionToSTLString(&try_catch); + log() << "js thread raised js exception: " << e << endl; + ret = v8::Undefined(); _sharedData->setErrored(true); - _sharedData->_returnData = BSON("ret" << BSONUndefined); } + // ret is translated to BSON to switch isolate + BSONObjBuilder b; + scope->v8ToMongoElement(b, "ret", ret); + _sharedData->_returnData = b.obj(); + } catch (const DBException& e) { + // Keeping behavior the same as for js exceptions. + log() << "js thread threw c++ exception: " << e.toString(); + _sharedData->setErrored(true); + _sharedData->_returnData = BSON("ret" << BSONUndefined); + } catch (const std::exception& e) { + log() << "js thread threw c++ exception: " << e.what(); + _sharedData->setErrored(true); + _sharedData->_returnData = BSON("ret" << BSONUndefined); + } catch (...) { + log() << "js thread threw c++ non-exception"; + _sharedData->setErrored(true); + _sharedData->_returnData = BSON("ret" << BSONUndefined); } + } - private: - std::shared_ptr<SharedData> _sharedData; - }; - - bool _started; - bool _done; - unique_ptr<stdx::thread> _thread; + private: std::shared_ptr<SharedData> _sharedData; }; - class CountDownLatchHolder { - private: - struct Latch { - Latch(int32_t count) : count(count) {} - stdx::condition_variable cv; - stdx::mutex mutex; - int32_t count; - }; - - std::shared_ptr<Latch> get(int32_t desc) { - stdx::lock_guard<stdx::mutex> lock(_mutex); - Map::iterator iter = _latches.find(desc); - jsassert(iter != _latches.end(), "not a valid CountDownLatch descriptor"); - return iter->second; - } + bool _started; + bool _done; + unique_ptr<stdx::thread> _thread; + std::shared_ptr<SharedData> _sharedData; +}; + +class CountDownLatchHolder { +private: + struct Latch { + Latch(int32_t count) : count(count) {} + stdx::condition_variable cv; + stdx::mutex mutex; + int32_t count; + }; - typedef std::map< int32_t, std::shared_ptr<Latch> > Map; - Map _latches; - stdx::mutex _mutex; - int32_t _counter; - public: - CountDownLatchHolder() : _counter(0) {} - int32_t make(int32_t count) { - jsassert(count >= 0, "argument must be >= 0"); - stdx::lock_guard<stdx::mutex> lock(_mutex); - int32_t desc = ++_counter; - _latches.insert(std::make_pair(desc, std::make_shared<Latch>(count))); - return desc; - } - void await(int32_t desc) { - std::shared_ptr<Latch> latch = get(desc); - stdx::unique_lock<stdx::mutex> lock(latch->mutex); - while (latch->count != 0) { - latch->cv.wait(lock); - } + std::shared_ptr<Latch> get(int32_t desc) { + stdx::lock_guard<stdx::mutex> lock(_mutex); + Map::iterator iter = _latches.find(desc); + jsassert(iter != _latches.end(), "not a valid CountDownLatch descriptor"); + return iter->second; + } + + typedef std::map<int32_t, std::shared_ptr<Latch>> Map; + Map _latches; + stdx::mutex _mutex; + int32_t _counter; + +public: + CountDownLatchHolder() : _counter(0) {} + int32_t make(int32_t count) { + jsassert(count >= 0, "argument must be >= 0"); + stdx::lock_guard<stdx::mutex> lock(_mutex); + int32_t desc = ++_counter; + _latches.insert(std::make_pair(desc, std::make_shared<Latch>(count))); + return desc; + } + void await(int32_t desc) { + std::shared_ptr<Latch> latch = get(desc); + stdx::unique_lock<stdx::mutex> lock(latch->mutex); + while (latch->count != 0) { + latch->cv.wait(lock); } - void countDown(int32_t desc) { - std::shared_ptr<Latch> latch = get(desc); - stdx::unique_lock<stdx::mutex> lock(latch->mutex); - if (latch->count > 0) { - latch->count--; - } - if (latch->count == 0) { - latch->cv.notify_all(); - } + } + void countDown(int32_t desc) { + std::shared_ptr<Latch> latch = get(desc); + stdx::unique_lock<stdx::mutex> lock(latch->mutex); + if (latch->count > 0) { + latch->count--; } - int32_t getCount(int32_t desc) { - std::shared_ptr<Latch> latch = get(desc); - stdx::unique_lock<stdx::mutex> lock(latch->mutex); - return latch->count; + if (latch->count == 0) { + latch->cv.notify_all(); } - }; - namespace { - CountDownLatchHolder globalCountDownLatchHolder; } - - v8::Handle<v8::Value> CountDownLatchNew(V8Scope* scope, const v8::Arguments& args) { - jsassert(args.Length() == 1, "need exactly one argument"); - jsassert(args[0]->IsInt32(), "argument must be an integer"); - int32_t count = v8::Local<v8::Integer>::Cast(args[0])->Value(); - return v8::Int32::New(globalCountDownLatchHolder.make(count)); + int32_t getCount(int32_t desc) { + std::shared_ptr<Latch> latch = get(desc); + stdx::unique_lock<stdx::mutex> lock(latch->mutex); + return latch->count; } +}; +namespace { +CountDownLatchHolder globalCountDownLatchHolder; +} - v8::Handle<v8::Value> CountDownLatchAwait(V8Scope* scope, const v8::Arguments& args) { - jsassert(args.Length() == 1, "need exactly one argument"); - jsassert(args[0]->IsInt32(), "argument must be an integer"); - globalCountDownLatchHolder.await(args[0]->ToInt32()->Value()); - return v8::Undefined(); - } +v8::Handle<v8::Value> CountDownLatchNew(V8Scope* scope, const v8::Arguments& args) { + jsassert(args.Length() == 1, "need exactly one argument"); + jsassert(args[0]->IsInt32(), "argument must be an integer"); + int32_t count = v8::Local<v8::Integer>::Cast(args[0])->Value(); + return v8::Int32::New(globalCountDownLatchHolder.make(count)); +} - v8::Handle<v8::Value> CountDownLatchCountDown(V8Scope* scope, const v8::Arguments& args) { - jsassert(args.Length() == 1, "need exactly one argument"); - jsassert(args[0]->IsInt32(), "argument must be an integer"); - globalCountDownLatchHolder.countDown(args[0]->ToInt32()->Value()); - return v8::Undefined(); - } +v8::Handle<v8::Value> CountDownLatchAwait(V8Scope* scope, const v8::Arguments& args) { + jsassert(args.Length() == 1, "need exactly one argument"); + jsassert(args[0]->IsInt32(), "argument must be an integer"); + globalCountDownLatchHolder.await(args[0]->ToInt32()->Value()); + return v8::Undefined(); +} - v8::Handle<v8::Value> CountDownLatchGetCount(V8Scope* scope, const v8::Arguments& args) { - jsassert(args.Length() == 1, "need exactly one argument"); - jsassert(args[0]->IsInt32(), "argument must be an integer"); - return v8::Int32::New(globalCountDownLatchHolder.getCount(args[0]->ToInt32()->Value())); - } +v8::Handle<v8::Value> CountDownLatchCountDown(V8Scope* scope, const v8::Arguments& args) { + jsassert(args.Length() == 1, "need exactly one argument"); + jsassert(args[0]->IsInt32(), "argument must be an integer"); + globalCountDownLatchHolder.countDown(args[0]->ToInt32()->Value()); + return v8::Undefined(); +} - JSThreadConfig *thisConfig(V8Scope* scope, const v8::Arguments& args) { - v8::Local<v8::External> c = v8::External::Cast( - *(args.This()->GetHiddenValue(v8::String::New("_JSThreadConfig")))); - JSThreadConfig *config = static_cast<std::shared_ptr<JSThreadConfig>*>(c->Value())->get(); - return config; - } +v8::Handle<v8::Value> CountDownLatchGetCount(V8Scope* scope, const v8::Arguments& args) { + jsassert(args.Length() == 1, "need exactly one argument"); + jsassert(args[0]->IsInt32(), "argument must be an integer"); + return v8::Int32::New(globalCountDownLatchHolder.getCount(args[0]->ToInt32()->Value())); +} - v8::Handle<v8::Value> ThreadInit(V8Scope* scope, const v8::Arguments& args) { - v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.This()); +JSThreadConfig* thisConfig(V8Scope* scope, const v8::Arguments& args) { + v8::Local<v8::External> c = + v8::External::Cast(*(args.This()->GetHiddenValue(v8::String::New("_JSThreadConfig")))); + JSThreadConfig* config = static_cast<std::shared_ptr<JSThreadConfig>*>(c->Value())->get(); + return config; +} - JSThreadConfig* config = new JSThreadConfig(scope, args); - v8::Local<v8::External> handle = scope->jsThreadConfigTracker.track(self, config); - args.This()->SetHiddenValue(v8::String::New("_JSThreadConfig"), handle); +v8::Handle<v8::Value> ThreadInit(V8Scope* scope, const v8::Arguments& args) { + v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.This()); - invariant(thisConfig(scope, args) == config); - return v8::Undefined(); - } + JSThreadConfig* config = new JSThreadConfig(scope, args); + v8::Local<v8::External> handle = scope->jsThreadConfigTracker.track(self, config); + args.This()->SetHiddenValue(v8::String::New("_JSThreadConfig"), handle); - v8::Handle<v8::Value> ScopedThreadInit(V8Scope* scope, const v8::Arguments& args) { - // NOTE: ScopedThread and Thread behave identically because a new V8 Isolate is always - // created. - return ThreadInit(scope, args); - } + invariant(thisConfig(scope, args) == config); + return v8::Undefined(); +} - v8::Handle<v8::Value> ThreadStart(V8Scope* scope, const v8::Arguments& args) { - thisConfig(scope, args)->start(); - return v8::Undefined(); - } +v8::Handle<v8::Value> ScopedThreadInit(V8Scope* scope, const v8::Arguments& args) { + // NOTE: ScopedThread and Thread behave identically because a new V8 Isolate is always + // created. + return ThreadInit(scope, args); +} - v8::Handle<v8::Value> ThreadJoin(V8Scope* scope, const v8::Arguments& args) { - thisConfig(scope, args)->join(); - return v8::Undefined(); - } +v8::Handle<v8::Value> ThreadStart(V8Scope* scope, const v8::Arguments& args) { + thisConfig(scope, args)->start(); + return v8::Undefined(); +} - // Indicates to the caller that the thread terminated as a result of an error. - v8::Handle<v8::Value> ThreadHasFailed(V8Scope* scope, const v8::Arguments& args) { - bool hasFailed = thisConfig(scope, args)->hasFailed(); - return v8::Boolean::New(hasFailed); - } +v8::Handle<v8::Value> ThreadJoin(V8Scope* scope, const v8::Arguments& args) { + thisConfig(scope, args)->join(); + return v8::Undefined(); +} - v8::Handle<v8::Value> ThreadReturnData(V8Scope* scope, const v8::Arguments& args) { - BSONObj data = thisConfig(scope, args)->returnData(); - return scope->mongoToV8Element(data.firstElement(), true); - } +// Indicates to the caller that the thread terminated as a result of an error. +v8::Handle<v8::Value> ThreadHasFailed(V8Scope* scope, const v8::Arguments& args) { + bool hasFailed = thisConfig(scope, args)->hasFailed(); + return v8::Boolean::New(hasFailed); +} - v8::Handle<v8::Value> ThreadInject(V8Scope* scope, const v8::Arguments& args) { - v8::HandleScope handle_scope; - jsassert(args.Length() == 1, "threadInject takes exactly 1 argument"); - jsassert(args[0]->IsObject(), "threadInject needs to be passed a prototype"); - v8::Local<v8::Object> o = args[0]->ToObject(); - - // install method on the Thread object - scope->injectV8Function("init", ThreadInit, o); - scope->injectV8Function("start", ThreadStart, o); - scope->injectV8Function("join", ThreadJoin, o); - scope->injectV8Function("hasFailed", ThreadHasFailed, o); - scope->injectV8Function("returnData", ThreadReturnData, o); - return handle_scope.Close(v8::Handle<v8::Value>()); - } +v8::Handle<v8::Value> ThreadReturnData(V8Scope* scope, const v8::Arguments& args) { + BSONObj data = thisConfig(scope, args)->returnData(); + return scope->mongoToV8Element(data.firstElement(), true); +} + +v8::Handle<v8::Value> ThreadInject(V8Scope* scope, const v8::Arguments& args) { + v8::HandleScope handle_scope; + jsassert(args.Length() == 1, "threadInject takes exactly 1 argument"); + jsassert(args[0]->IsObject(), "threadInject needs to be passed a prototype"); + v8::Local<v8::Object> o = args[0]->ToObject(); + + // install method on the Thread object + scope->injectV8Function("init", ThreadInit, o); + scope->injectV8Function("start", ThreadStart, o); + scope->injectV8Function("join", ThreadJoin, o); + scope->injectV8Function("hasFailed", ThreadHasFailed, o); + scope->injectV8Function("returnData", ThreadReturnData, o); + return handle_scope.Close(v8::Handle<v8::Value>()); +} - v8::Handle<v8::Value> ScopedThreadInject(V8Scope* scope, const v8::Arguments& args) { - v8::HandleScope handle_scope; - jsassert(args.Length() == 1, "threadInject takes exactly 1 argument"); - jsassert(args[0]->IsObject(), "threadInject needs to be passed a prototype"); - v8::Local<v8::Object> o = args[0]->ToObject(); +v8::Handle<v8::Value> ScopedThreadInject(V8Scope* scope, const v8::Arguments& args) { + v8::HandleScope handle_scope; + jsassert(args.Length() == 1, "threadInject takes exactly 1 argument"); + jsassert(args[0]->IsObject(), "threadInject needs to be passed a prototype"); + v8::Local<v8::Object> o = args[0]->ToObject(); - scope->injectV8Function("init", ScopedThreadInit, o); - // inheritance takes care of other member functions + scope->injectV8Function("init", ScopedThreadInit, o); + // inheritance takes care of other member functions - return handle_scope.Close(v8::Handle<v8::Value>()); - } + return handle_scope.Close(v8::Handle<v8::Value>()); +} - void installFork(V8Scope* scope, v8::Handle<v8::Object>& global, - v8::Handle<v8::Context>& context) { - scope->injectV8Function("_threadInject", ThreadInject, global); - scope->injectV8Function("_scopedThreadInject", ScopedThreadInject, global); - - scope->setObject("CountDownLatch", BSONObj(), false); - v8::Handle<v8::Object> cdl = scope->get("CountDownLatch").As<v8::Object>(); - scope->injectV8Function("_new", CountDownLatchNew, cdl); - scope->injectV8Function("_await", CountDownLatchAwait, cdl); - scope->injectV8Function("_countDown", CountDownLatchCountDown, cdl); - scope->injectV8Function("_getCount", CountDownLatchGetCount, cdl); - } +void installFork(V8Scope* scope, v8::Handle<v8::Object>& global, v8::Handle<v8::Context>& context) { + scope->injectV8Function("_threadInject", ThreadInject, global); + scope->injectV8Function("_scopedThreadInject", ScopedThreadInject, global); - v8::Handle<v8::Value> v8AssertionException(const char* errorMessage) { - return v8::ThrowException(v8::Exception::Error(v8::String::New(errorMessage))); - } - v8::Handle<v8::Value> v8AssertionException(const std::string& errorMessage) { - return v8AssertionException(errorMessage.c_str()); - } + scope->setObject("CountDownLatch", BSONObj(), false); + v8::Handle<v8::Object> cdl = scope->get("CountDownLatch").As<v8::Object>(); + scope->injectV8Function("_new", CountDownLatchNew, cdl); + scope->injectV8Function("_await", CountDownLatchAwait, cdl); + scope->injectV8Function("_countDown", CountDownLatchCountDown, cdl); + scope->injectV8Function("_getCount", CountDownLatchGetCount, cdl); +} + +v8::Handle<v8::Value> v8AssertionException(const char* errorMessage) { + return v8::ThrowException(v8::Exception::Error(v8::String::New(errorMessage))); +} +v8::Handle<v8::Value> v8AssertionException(const std::string& errorMessage) { + return v8AssertionException(errorMessage.c_str()); +} } |