2016-03-12 18:50:43 +00:00
# include "Task.h"
# include "Database.h"
# include "File.h"
# include "Serialize.h"
# include "Socket.h"
# include "TaskStub.h"
# include "TaskTryCatch.h"
# include "TlsContextWrapper.h"
# include <algorithm>
# include <assert.h>
# include <cstring>
# include <fstream>
# include <iostream>
# include <libplatform/libplatform.h>
# include <map>
# include <sys/types.h>
# include <uv.h>
# include <v8.h>
# include <v8-platform.h>
# ifdef _WIN32
static const int STDIN_FILENO = 0 ;
# else
# include <unistd.h>
# endif
extern v8 : : Platform * gPlatform ;
int gNextTaskId = 1 ;
int Task : : _count ;
struct ExportRecord {
v8 : : Persistent < v8 : : Function , v8 : : CopyablePersistentTraits < v8 : : Function > > _persistent ;
int _useCount ;
ExportRecord ( v8 : : Isolate * isolate , v8 : : Handle < v8 : : Function > function )
: _persistent ( isolate , function ) ,
_useCount ( 0 ) {
}
void ref ( ) {
+ + _useCount ;
}
bool release ( ) {
return - - _useCount = = 0 ;
}
} ;
struct ImportRecord {
v8 : : Persistent < v8 : : Function , v8 : : CopyablePersistentTraits < v8 : : Function > > _persistent ;
exportid_t _export ;
taskid_t _task ;
Task * _owner ;
int _useCount ;
ImportRecord ( v8 : : Isolate * isolate , v8 : : Handle < v8 : : Function > function , exportid_t exportId , taskid_t taskId , Task * owner )
: _persistent ( isolate , function ) ,
_export ( exportId ) ,
_task ( taskId ) ,
_owner ( owner ) ,
_useCount ( 0 ) {
_persistent . SetWeak ( this , ImportRecord : : onRelease ) ;
}
void ref ( ) {
if ( _useCount + + = = 0 ) {
// Make a strong ref again until an in-flight function call is finished.
_persistent . ClearWeak ( ) ;
}
}
void release ( ) {
if ( - - _useCount = = 0 ) {
// All in-flight calls are finished. Make weak.
_persistent . SetWeak ( this , ImportRecord : : onRelease ) ;
}
}
static void onRelease ( const v8 : : WeakCallbackData < v8 : : Function , ImportRecord > & data ) {
ImportRecord * import = data . GetParameter ( ) ;
import - > _owner - > releaseExport ( import - > _task , import - > _export ) ;
for ( size_t i = 0 ; i < import - > _owner - > _imports . size ( ) ; + + i ) {
if ( import - > _owner - > _imports [ i ] = = import ) {
import - > _owner - > _imports . erase ( import - > _owner - > _imports . begin ( ) + i ) ;
break ;
}
}
import - > _persistent . Reset ( ) ;
delete import ;
}
} ;
Task : : Task ( ) {
_loop = uv_loop_new ( ) ;
+ + _count ;
v8 : : Isolate : : CreateParams options ;
options . array_buffer_allocator = & _allocator ;
_isolate = v8 : : Isolate : : New ( options ) ;
_isolate - > SetData ( 0 , this ) ;
_isolate - > SetCaptureStackTraceForUncaughtExceptions ( true , 16 ) ;
}
Task : : ~ Task ( ) {
2016-04-09 15:31:12 +00:00
_exportObject . Reset ( ) ;
2016-04-16 21:30:52 +00:00
_sourceObject . Reset ( ) ;
2016-04-09 15:31:12 +00:00
2016-03-12 18:50:43 +00:00
{
v8 : : Isolate : : Scope isolateScope ( _isolate ) ;
v8 : : HandleScope handleScope ( _isolate ) ;
_context . Reset ( ) ;
}
_isolate - > Dispose ( ) ;
_isolate = 0 ;
uv_loop_delete ( _loop ) ;
- - _count ;
}
v8 : : Handle < v8 : : Context > Task : : getContext ( ) {
return v8 : : Local < v8 : : Context > : : New ( _isolate , _context ) ;
}
void Task : : run ( ) {
{
v8 : : Isolate : : Scope isolateScope ( _isolate ) ;
v8 : : HandleScope handleScope ( _isolate ) ;
v8 : : Context : : Scope contextScope ( v8 : : Local < v8 : : Context > : : New ( _isolate , _context ) ) ;
uv_run ( _loop , UV_RUN_DEFAULT ) ;
}
_promises . clear ( ) ;
_exports . clear ( ) ;
_imports . clear ( ) ;
}
v8 : : Handle < v8 : : String > Task : : loadFile ( v8 : : Isolate * isolate , const char * fileName ) {
v8 : : Handle < v8 : : String > value ;
std : : ifstream file ( fileName , std : : ios_base : : in | std : : ios_base : : binary | std : : ios_base : : ate ) ;
std : : streampos fileSize = file . tellg ( ) ;
if ( fileSize > = 0 ) {
file . seekg ( 0 , std : : ios_base : : beg ) ;
char * buffer = new char [ fileSize ] ;
file . read ( buffer , fileSize ) ;
std : : string contents ( buffer , buffer + fileSize ) ;
value = v8 : : String : : NewFromOneByte ( isolate , reinterpret_cast < const uint8_t * > ( buffer ) , v8 : : String : : kNormalString , fileSize ) ;
delete [ ] buffer ;
}
return value ;
}
void Task : : activate ( ) {
v8 : : Isolate : : Scope isolateScope ( _isolate ) ;
v8 : : HandleScope handleScope ( _isolate ) ;
v8 : : Handle < v8 : : ObjectTemplate > global = v8 : : ObjectTemplate : : New ( ) ;
if ( ! _importObject . IsEmpty ( ) ) {
v8 : : Local < v8 : : Object > imports ( _importObject . Get ( _isolate ) ) ;
v8 : : Handle < v8 : : Array > keys = imports - > GetOwnPropertyNames ( ) ;
for ( size_t i = 0 ; i < keys - > Length ( ) ; + + i ) {
global - > SetAccessor ( keys - > Get ( i ) . As < v8 : : String > ( ) , getImportProperty ) ;
}
}
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " print " ) , v8 : : FunctionTemplate : : New ( _isolate , print ) ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " setTimeout " ) , v8 : : FunctionTemplate : : New ( _isolate , setTimeout ) ) ;
global - > SetAccessor ( v8 : : String : : NewFromUtf8 ( _isolate , " parent " ) , parent ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " exit " ) , v8 : : FunctionTemplate : : New ( _isolate , exit ) ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " utf8Length " ) , v8 : : FunctionTemplate : : New ( _isolate , utf8Length ) ) ;
global - > SetAccessor ( v8 : : String : : NewFromUtf8 ( _isolate , " exports " ) , getExports , setExports ) ;
global - > SetAccessor ( v8 : : String : : NewFromUtf8 ( _isolate , " imports " ) , getImports ) ;
global - > SetAccessor ( v8 : : String : : NewFromUtf8 ( _isolate , " version " ) , version ) ;
global - > SetAccessor ( v8 : : String : : NewFromUtf8 ( _isolate , " statistics " ) , statistics ) ;
if ( _trusted ) {
2016-04-16 21:30:52 +00:00
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " require " ) , v8 : : FunctionTemplate : : New ( _isolate , require ) ) ;
2016-03-12 18:50:43 +00:00
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " Database " ) , v8 : : FunctionTemplate : : New ( _isolate , Database : : create ) ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " Socket " ) , v8 : : FunctionTemplate : : New ( _isolate , Socket : : create ) ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " Task " ) , v8 : : FunctionTemplate : : New ( _isolate , TaskStub : : create ) ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " TlsContext " ) , v8 : : FunctionTemplate : : New ( _isolate , TlsContextWrapper : : create ) ) ;
File : : configure ( _isolate , global ) ;
2016-04-16 21:30:52 +00:00
} else {
global - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " require " ) , v8 : : FunctionTemplate : : New ( _isolate , childRequire ) ) ;
2016-03-12 18:50:43 +00:00
}
v8 : : Local < v8 : : Context > context = v8 : : Context : : New ( _isolate , 0 , global ) ;
_context = v8 : : Persistent < v8 : : Context , v8 : : CopyablePersistentTraits < v8 : : Context > > ( _isolate , context ) ;
2016-04-09 15:24:48 +00:00
v8 : : Context : : Scope contextScope ( v8 : : Local < v8 : : Context > : : New ( _isolate , _context ) ) ;
v8 : : Local < v8 : : Object > exportObject = v8 : : Object : : New ( _isolate ) ;
_exportObject = v8 : : Persistent < v8 : : Object , v8 : : CopyablePersistentTraits < v8 : : Object > > ( _isolate , exportObject ) ;
2016-03-12 18:50:43 +00:00
}
void Task : : activate ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
Task * task = Task : : get ( args . GetIsolate ( ) ) ;
task - > activate ( ) ;
}
void Task : : print ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
v8 : : HandleScope scope ( args . GetIsolate ( ) ) ;
v8 : : Local < v8 : : Context > context = args . GetIsolate ( ) - > GetCurrentContext ( ) ;
v8 : : Handle < v8 : : Object > json = context - > Global ( ) - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " JSON " ) ) - > ToObject ( ) ;
v8 : : Handle < v8 : : Function > stringify = v8 : : Handle < v8 : : Function > : : Cast ( json - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " stringify " ) ) ) ;
Task * task = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
TaskTryCatch tryCatch ( task ) ;
std : : cout < < " Task[ " < < task < < ' : ' < < task - > _scriptName < < " ]> " ;
for ( int i = 0 ; i < args . Length ( ) ; i + + ) {
std : : cout < < ' ' ;
v8 : : Handle < v8 : : Value > arg = args [ i ] ;
if ( arg - > IsNativeError ( ) ) {
arg = Serialize : : storeMessage ( task , v8 : : Exception : : CreateMessage ( arg ) ) ;
}
v8 : : String : : Utf8Value value ( stringify - > Call ( json , 1 , & arg ) ) ;
std : : cout < < ( * value ? * value : " (null) " ) ;
}
std : : cout < < ' \n ' ;
}
struct TimeoutData {
Task * _task ;
v8 : : Persistent < v8 : : Function , v8 : : CopyablePersistentTraits < v8 : : Function > > _callback ;
} ;
void Task : : setTimeout ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
v8 : : HandleScope scope ( args . GetIsolate ( ) ) ;
Task * task = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
TimeoutData * timeout = new TimeoutData ( ) ;
timeout - > _task = task ;
v8 : : Persistent < v8 : : Function , v8 : : CopyablePersistentTraits < v8 : : Function > > function ( args . GetIsolate ( ) , v8 : : Handle < v8 : : Function > : : Cast ( args [ 0 ] ) ) ;
timeout - > _callback = function ;
uv_timer_t * timer = new uv_timer_t ( ) ;
uv_timer_init ( task - > _loop , timer ) ;
timer - > data = timeout ;
uv_timer_start ( timer , timeoutCallback , static_cast < uint64_t > ( args [ 1 ] . As < v8 : : Number > ( ) - > Value ( ) ) , 0 ) ;
}
void Task : : timeoutCallback ( uv_timer_t * handle ) {
TimeoutData * timeout = reinterpret_cast < TimeoutData * > ( handle - > data ) ;
TaskTryCatch tryCatch ( timeout - > _task ) ;
v8 : : HandleScope scope ( timeout - > _task - > _isolate ) ;
v8 : : Handle < v8 : : Function > function = v8 : : Local < v8 : : Function > : : New ( timeout - > _task - > _isolate , timeout - > _callback ) ;
function - > Call ( v8 : : Undefined ( timeout - > _task - > _isolate ) , 0 , 0 ) ;
delete timeout ;
}
void Task : : utf8Length ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
Task * task = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
TaskTryCatch tryCatch ( task ) ;
v8 : : HandleScope scope ( task - > _isolate ) ;
args . GetReturnValue ( ) . Set ( v8 : : Integer : : New ( args . GetIsolate ( ) , args [ 0 ] . As < v8 : : String > ( ) - > Utf8Length ( ) ) ) ;
}
void Task : : exit ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
: : exit ( args [ 0 ] - > Int32Value ( ) ) ;
}
void Task : : kill ( ) {
if ( ! _killed & & _isolate ) {
_killed = true ;
v8 : : V8 : : TerminateExecution ( _isolate ) ;
}
}
2016-03-13 13:37:58 +00:00
bool Task : : execute ( const char * fileName ) {
bool executed = false ;
2016-03-12 18:50:43 +00:00
v8 : : Isolate : : Scope isolateScope ( _isolate ) ;
v8 : : HandleScope handleScope ( _isolate ) ;
v8 : : Context : : Scope contextScope ( v8 : : Local < v8 : : Context > : : New ( _isolate , _context ) ) ;
v8 : : Handle < v8 : : String > name = v8 : : String : : NewFromUtf8 ( _isolate , fileName ) ;
v8 : : Handle < v8 : : String > source = loadFile ( _isolate , fileName ) ;
std : : cout < < " Running script " < < fileName < < " \n " ;
if ( ! _scriptName . size ( ) ) {
_scriptName = fileName ;
}
2016-04-09 15:24:48 +00:00
if ( ! _path . size ( ) ) {
std : : string path = _scriptName ;
size_t position = path . rfind ( ' / ' ) ;
if ( position ! = std : : string : : npos ) {
path . resize ( position + 1 ) ;
} else {
path = " . " ;
}
_path . push_back ( path ) ;
}
2016-03-12 18:50:43 +00:00
if ( ! source . IsEmpty ( ) ) {
v8 : : Handle < v8 : : Script > script = v8 : : Script : : Compile ( source , name ) ;
if ( ! script . IsEmpty ( ) ) {
script - > Run ( ) ;
std : : cout < < " Script " < < fileName < < " completed \n " ;
2016-03-13 13:37:58 +00:00
executed = true ;
2016-03-12 18:50:43 +00:00
} else {
std : : cerr < < " Failed to compile: " < < fileName < < " . \n " ;
}
} else {
std : : string message ;
message = " Failed to load file: " ;
message + = fileName ;
_isolate - > ThrowException ( v8 : : Exception : : Error ( v8 : : String : : NewFromUtf8 ( _isolate , message . c_str ( ) ) ) ) ;
}
2016-03-13 13:37:58 +00:00
return executed ;
2016-03-12 18:50:43 +00:00
}
void Task : : invokeExport ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
Task * sender = Task : : get ( args . GetIsolate ( ) ) ;
v8 : : Handle < v8 : : Object > data = v8 : : Handle < v8 : : Object > : : Cast ( args . Data ( ) ) ;
exportid_t exportId = data - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " export " ) ) - > Int32Value ( ) ;
taskid_t recipientId = data - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " task " ) ) - > Int32Value ( ) ;
for ( size_t i = 0 ; i < sender - > _imports . size ( ) ; + + i ) {
if ( sender - > _imports [ i ] - > _task = = recipientId & & sender - > _imports [ i ] - > _export = = exportId ) {
sender - > _imports [ i ] - > ref ( ) ;
break ;
}
}
v8 : : Local < v8 : : Array > array = v8 : : Array : : New ( args . GetIsolate ( ) , args . Length ( ) + 1 ) ;
for ( int i = 0 ; i < args . Length ( ) ; + + i ) {
array - > Set ( i + 1 , args [ i ] ) ;
}
if ( TaskStub * recipient = sender - > get ( recipientId ) ) {
promiseid_t promise = sender - > allocatePromise ( ) ;
sendPromiseExportMessage ( sender , recipient , kInvokeExport , promise , exportId , array ) ;
args . GetReturnValue ( ) . Set ( sender - > getPromise ( promise ) ) ;
} else {
args . GetReturnValue ( ) . Set ( args . GetIsolate ( ) - > ThrowException ( v8 : : Exception : : Error ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " Invoking a function on a nonexistant task. " ) ) ) ) ;
}
}
v8 : : Handle < v8 : : Value > Task : : invokeExport ( TaskStub * from , Task * to , exportid_t exportId , const std : : vector < char > & buffer ) {
v8 : : Handle < v8 : : Value > result ;
if ( to - > _exports [ exportId ] ) {
v8 : : Handle < v8 : : Array > arguments = v8 : : Handle < v8 : : Array > : : Cast ( Serialize : : load ( to , from , buffer ) ) ;
std : : vector < v8 : : Handle < v8 : : Value > > argumentArray ;
for ( size_t i = 1 ; i < arguments - > Length ( ) ; + + i ) {
argumentArray . push_back ( arguments - > Get ( i ) ) ;
}
v8 : : Handle < v8 : : Function > function = v8 : : Local < v8 : : Function > : : New ( to - > _isolate , to - > _exports [ exportId ] - > _persistent ) ;
v8 : : Handle < v8 : : Value > * argumentPointer = 0 ;
if ( argumentArray . size ( ) ) {
argumentPointer = & * argumentArray . begin ( ) ;
}
result = function - > Call ( v8 : : Handle < v8 : : Object > : : Cast ( arguments - > Get ( 0 ) ) , argumentArray . size ( ) , argumentPointer ) ;
} else {
std : : cout < < to - > _scriptName < < " : That's not an export we have (exportId= " < < exportId < < " , exports = " < < to - > _exports . size ( ) < < " ) \n " ;
}
from - > getStream ( ) . send ( kReleaseImport , reinterpret_cast < char * > ( & exportId ) , sizeof ( exportId ) ) ;
return result ;
}
void Task : : sendPromiseResolve ( Task * from , TaskStub * to , promiseid_t promise , v8 : : Handle < v8 : : Value > result ) {
if ( ! result . IsEmpty ( ) & & result - > IsPromise ( ) ) {
// We're not going to serialize/deserialize a promise...
v8 : : Handle < v8 : : Object > data = v8 : : Object : : New ( from - > _isolate ) ;
data - > Set ( v8 : : String : : NewFromUtf8 ( from - > _isolate , " task " ) , v8 : : Int32 : : New ( from - > _isolate , to - > getId ( ) ) ) ;
data - > Set ( v8 : : String : : NewFromUtf8 ( from - > _isolate , " promise " ) , v8 : : Int32 : : New ( from - > _isolate , promise ) ) ;
v8 : : Handle < v8 : : Promise > promise = v8 : : Handle < v8 : : Promise > : : Cast ( result ) ;
v8 : : Handle < v8 : : Function > then = v8 : : Function : : New ( from - > _isolate , invokeThen , data ) ;
promise - > Then ( then ) ;
v8 : : Handle < v8 : : Function > catchCallback = v8 : : Function : : New ( from - > _isolate , invokeCatch , data ) ;
promise - > Catch ( catchCallback ) ;
from - > _isolate - > RunMicrotasks ( ) ;
} else {
sendPromiseMessage ( from , to , kResolvePromise , promise , result ) ;
}
}
void Task : : sendPromiseReject ( Task * from , TaskStub * to , promiseid_t promise , v8 : : Handle < v8 : : Value > result ) {
if ( ! result . IsEmpty ( ) & & result - > IsPromise ( ) ) {
// We're not going to serialize/deserialize a promise...
v8 : : Handle < v8 : : Object > data = v8 : : Object : : New ( from - > _isolate ) ;
data - > Set ( v8 : : String : : NewFromUtf8 ( from - > _isolate , " task " ) , v8 : : Int32 : : New ( from - > _isolate , to - > getId ( ) ) ) ;
data - > Set ( v8 : : String : : NewFromUtf8 ( from - > _isolate , " promise " ) , v8 : : Int32 : : New ( from - > _isolate , promise ) ) ;
v8 : : Handle < v8 : : Promise > promise = v8 : : Handle < v8 : : Promise > : : Cast ( result ) ;
v8 : : Handle < v8 : : Function > then = v8 : : Function : : New ( from - > _isolate , invokeThen , data ) ;
promise - > Then ( then ) ;
v8 : : Handle < v8 : : Function > catchCallback = v8 : : Function : : New ( from - > _isolate , invokeCatch , data ) ;
promise - > Catch ( catchCallback ) ;
from - > _isolate - > RunMicrotasks ( ) ;
} else {
sendPromiseMessage ( from , to , kRejectPromise , promise , result ) ;
}
}
void Task : : sendPromiseMessage ( Task * from , TaskStub * to , MessageType messageType , promiseid_t promise , v8 : : Handle < v8 : : Value > result ) {
if ( to ) {
std : : vector < char > buffer ;
buffer . insert ( buffer . end ( ) , reinterpret_cast < char * > ( & promise ) , reinterpret_cast < char * > ( & promise ) + sizeof ( promise ) ) ;
if ( ! result . IsEmpty ( ) & & ! result - > IsUndefined ( ) & & ! result - > IsNull ( ) ) {
Serialize : : store ( from , buffer , result ) ;
}
to - > getStream ( ) . send ( messageType , & * buffer . begin ( ) , buffer . size ( ) ) ;
} else {
std : : cerr < < " Sending to a NULL task. \n " ;
}
}
void Task : : sendPromiseExportMessage ( Task * from , TaskStub * to , MessageType messageType , promiseid_t promise , exportid_t exportId , v8 : : Handle < v8 : : Value > result ) {
std : : vector < char > buffer ;
buffer . insert ( buffer . end ( ) , reinterpret_cast < char * > ( & promise ) , reinterpret_cast < char * > ( & promise ) + sizeof ( promise ) ) ;
buffer . insert ( buffer . end ( ) , reinterpret_cast < char * > ( & exportId ) , reinterpret_cast < char * > ( & exportId ) + sizeof ( exportId ) ) ;
if ( ! result . IsEmpty ( ) & & ! result - > IsUndefined ( ) & & ! result - > IsNull ( ) ) {
Serialize : : store ( from , buffer , result ) ;
}
to - > getStream ( ) . send ( messageType , & * buffer . begin ( ) , buffer . size ( ) ) ;
}
TaskStub * Task : : get ( taskid_t taskId ) {
return taskId = = kParentId ? _parent : _children [ taskId ] ;
}
void Task : : invokeThen ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
Task * from = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
v8 : : Handle < v8 : : Object > data = v8 : : Handle < v8 : : Object > : : Cast ( args . Data ( ) ) ;
TaskStub * to = from - > get ( data - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " task " ) ) - > Int32Value ( ) ) ;
promiseid_t promise = data - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " promise " ) ) - > Int32Value ( ) ;
sendPromiseMessage ( from , to , kResolvePromise , promise , args [ 0 ] ) ;
}
void Task : : invokeCatch ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
Task * from = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
v8 : : Handle < v8 : : Object > data = v8 : : Handle < v8 : : Object > : : Cast ( args . Data ( ) ) ;
TaskStub * to = from - > get ( data - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " task " ) ) - > Int32Value ( ) ) ;
promiseid_t promise = data - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " promise " ) ) - > Int32Value ( ) ;
sendPromiseMessage ( from , to , kRejectPromise , promise , args [ 0 ] ) ;
}
void Task : : parent ( v8 : : Local < v8 : : String > property , const v8 : : PropertyCallbackInfo < v8 : : Value > & args ) {
Task * task = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
if ( task - > _parent ) {
args . GetReturnValue ( ) . Set ( task - > _parent - > getTaskObject ( ) ) ;
} else {
args . GetReturnValue ( ) . Set ( v8 : : Undefined ( task - > _isolate ) ) ;
}
}
void Task : : version ( v8 : : Local < v8 : : String > property , const v8 : : PropertyCallbackInfo < v8 : : Value > & args ) {
Task * task = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
args . GetReturnValue ( ) . Set ( v8 : : String : : NewFromUtf8 ( task - > _isolate , v8 : : V8 : : GetVersion ( ) ) ) ;
}
void Task : : getImportProperty ( v8 : : Local < v8 : : String > property , const v8 : : PropertyCallbackInfo < v8 : : Value > & args ) {
v8 : : Local < v8 : : Object > imports = Task : : get ( args . GetIsolate ( ) ) - > _importObject . Get ( args . GetIsolate ( ) ) ;
args . GetReturnValue ( ) . Set ( imports - > Get ( property ) ) ;
}
void Task : : getImports ( v8 : : Local < v8 : : String > property , const v8 : : PropertyCallbackInfo < v8 : : Value > & args ) {
args . GetReturnValue ( ) . Set ( v8 : : Local < v8 : : Object > : : New ( args . GetIsolate ( ) , Task : : get ( args . GetIsolate ( ) ) - > _importObject ) ) ;
}
void Task : : getExports ( v8 : : Local < v8 : : String > property , const v8 : : PropertyCallbackInfo < v8 : : Value > & args ) {
args . GetReturnValue ( ) . Set ( v8 : : Local < v8 : : Object > : : New ( args . GetIsolate ( ) , Task : : get ( args . GetIsolate ( ) ) - > _exportObject ) ) ;
}
void Task : : setExports ( v8 : : Local < v8 : : String > property , v8 : : Local < v8 : : Value > value , const v8 : : PropertyCallbackInfo < void > & args ) {
Task : : get ( args . GetIsolate ( ) ) - > _exportObject = v8 : : Persistent < v8 : : Object , v8 : : CopyablePersistentTraits < v8 : : Object > > ( args . GetIsolate ( ) , v8 : : Handle < v8 : : Object > : : Cast ( value ) ) ;
}
Task * Task : : get ( v8 : : Isolate * isolate ) {
return reinterpret_cast < Task * > ( isolate - > GetData ( 0 ) ) ;
}
promiseid_t Task : : allocatePromise ( ) {
promiseid_t promiseId ;
do {
promiseId = _nextPromise + + ;
} while ( _promises . find ( promiseId ) ! = _promises . end ( ) ) ;
v8 : : Persistent < v8 : : Promise : : Resolver , v8 : : NonCopyablePersistentTraits < v8 : : Promise : : Resolver > > promise ( _isolate , v8 : : Promise : : Resolver : : New ( _isolate ) ) ;
_promises [ promiseId ] = promise ;
return promiseId ;
}
v8 : : Handle < v8 : : Promise : : Resolver > Task : : getPromise ( promiseid_t promise ) {
v8 : : Handle < v8 : : Promise : : Resolver > result ;
if ( ! _promises [ promise ] . IsEmpty ( ) ) {
result = v8 : : Local < v8 : : Promise : : Resolver > : : New ( _isolate , _promises [ promise ] ) ;
}
return result ;
}
void Task : : resolvePromise ( promiseid_t promise , v8 : : Handle < v8 : : Value > value ) {
TaskTryCatch tryCatch ( this ) ;
if ( ! _promises [ promise ] . IsEmpty ( ) ) {
v8 : : HandleScope handleScope ( _isolate ) ;
v8 : : Handle < v8 : : Promise : : Resolver > resolver = v8 : : Local < v8 : : Promise : : Resolver > : : New ( _isolate , _promises [ promise ] ) ;
resolver - > Resolve ( value ) ;
_isolate - > RunMicrotasks ( ) ;
_promises [ promise ] . Reset ( ) ;
_promises . erase ( promise ) ;
}
}
void Task : : rejectPromise ( promiseid_t promise , v8 : : Handle < v8 : : Value > value ) {
TaskTryCatch tryCatch ( this ) ;
if ( ! _promises [ promise ] . IsEmpty ( ) ) {
v8 : : HandleScope handleScope ( _isolate ) ;
v8 : : Handle < v8 : : Promise : : Resolver > resolver = v8 : : Local < v8 : : Promise : : Resolver > : : New ( _isolate , _promises [ promise ] ) ;
resolver - > Reject ( value ) ;
_isolate - > RunMicrotasks ( ) ;
_promises [ promise ] . Reset ( ) ;
_promises . erase ( promise ) ;
}
}
exportid_t Task : : exportFunction ( v8 : : Handle < v8 : : Function > function ) {
exportid_t exportId = - 1 ;
v8 : : Handle < v8 : : String > exportName = v8 : : String : : NewFromUtf8 ( _isolate , " export " ) ;
v8 : : Local < v8 : : Value > value = function - > GetHiddenValue ( exportName ) ;
if ( ! value . IsEmpty ( ) & & value - > IsNumber ( ) )
{
exportid_t foundId = value - > ToInteger ( _isolate ) - > Int32Value ( ) ;
if ( _exports [ foundId ] ) {
exportId = foundId ;
}
}
if ( exportId = = - 1 ) {
do {
exportId = _nextExport + + ;
} while ( _exports [ _nextExport ] ) ;
ExportRecord * record = new ExportRecord ( _isolate , function ) ;
function - > SetHiddenValue ( exportName , v8 : : Integer : : New ( _isolate , exportId ) ) ;
_exports [ exportId ] = record ;
}
if ( _exports [ exportId ] ) {
_exports [ exportId ] - > ref ( ) ;
}
return exportId ;
}
void Task : : releaseExport ( taskid_t taskId , exportid_t exportId ) {
if ( TaskStub * task = get ( taskId ) ) {
std : : vector < char > buffer ;
buffer . insert ( buffer . end ( ) , reinterpret_cast < char * > ( & exportId ) , reinterpret_cast < char * > ( & exportId ) + sizeof ( exportId ) ) ;
task - > getStream ( ) . send ( kReleaseExport , & * buffer . begin ( ) , buffer . size ( ) ) ;
}
}
v8 : : Handle < v8 : : Function > Task : : addImport ( taskid_t taskId , exportid_t exportId ) {
v8 : : Local < v8 : : Object > data = v8 : : Object : : New ( _isolate ) ;
data - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " export " ) , v8 : : Int32 : : New ( _isolate , exportId ) ) ;
data - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " task " ) , v8 : : Int32 : : New ( _isolate , taskId ) ) ;
v8 : : Local < v8 : : Function > function = v8 : : Function : : New ( _isolate , Task : : invokeExport , data ) ;
_imports . push_back ( new ImportRecord ( _isolate , function , exportId , taskId , this ) ) ;
return function ;
}
void Task : : statistics ( v8 : : Local < v8 : : String > property , const v8 : : PropertyCallbackInfo < v8 : : Value > & args ) {
Task * task = reinterpret_cast < Task * > ( args . GetIsolate ( ) - > GetData ( 0 ) ) ;
args . GetReturnValue ( ) . Set ( task - > getStatistics ( ) ) ;
}
v8 : : Handle < v8 : : Object > Task : : getStatistics ( ) {
v8 : : Handle < v8 : : Object > result = v8 : : Object : : New ( _isolate ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " sockets " ) , v8 : : Integer : : New ( _isolate , Socket : : getCount ( ) ) ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " openSockets " ) , v8 : : Integer : : New ( _isolate , Socket : : getOpenCount ( ) ) ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " promises " ) , v8 : : Integer : : New ( _isolate , _promises . size ( ) ) ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " exports " ) , v8 : : Integer : : New ( _isolate , _exports . size ( ) ) ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " imports " ) , v8 : : Integer : : New ( _isolate , _imports . size ( ) ) ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " tlsContexts " ) , v8 : : Integer : : New ( _isolate , TlsContextWrapper : : getCount ( ) ) ) ;
uv_rusage_t usage ;
if ( uv_getrusage ( & usage ) = = 0 ) {
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " utime " ) , v8 : : Number : : New ( _isolate , usage . ru_utime . tv_sec + usage . ru_utime . tv_usec / 1000000.0 ) ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " stime " ) , v8 : : Number : : New ( _isolate , usage . ru_stime . tv_sec + usage . ru_stime . tv_usec / 1000000.0 ) ) ;
result - > Set ( v8 : : String : : NewFromUtf8 ( _isolate , " maxrss " ) , v8 : : Number : : New ( _isolate , usage . ru_maxrss ) ) ;
}
return result ;
}
void Task : : onReceivePacket ( int packetType , const char * begin , size_t length , void * userData ) {
TaskStub * stub = reinterpret_cast < TaskStub * > ( userData ) ;
TaskStub * from = stub ;
Task * to = stub - > getOwner ( ) ;
TaskTryCatch tryCatch ( to ) ;
v8 : : HandleScope scope ( to - > _isolate ) ;
switch ( static_cast < MessageType > ( packetType ) ) {
case kStatistics :
{
promiseid_t promise ;
std : : memcpy ( & promise , begin , sizeof ( promise ) ) ;
v8 : : Handle < v8 : : Value > result = to - > getStatistics ( ) ;
sendPromiseResolve ( to , from , promise , result ) ;
}
break ;
case kInvokeExport :
{
promiseid_t promise ;
exportid_t exportId ;
std : : memcpy ( & promise , begin , sizeof ( promise ) ) ;
std : : memcpy ( & exportId , begin + sizeof ( promise ) , sizeof ( exportId ) ) ;
v8 : : TryCatch tryCatch ;
v8 : : Handle < v8 : : Value > result = invokeExport ( from , to , exportId , std : : vector < char > ( begin + sizeof ( promiseid_t ) + sizeof ( exportid_t ) , begin + length ) ) ;
if ( tryCatch . HasCaught ( ) ) {
sendPromiseReject ( to , from , promise , Serialize : : store ( to , tryCatch ) ) ;
} else {
sendPromiseResolve ( to , from , promise , result ) ;
}
}
break ;
case kResolvePromise :
case kRejectPromise :
{
v8 : : Handle < v8 : : Value > arg ;
promiseid_t promise ;
std : : memcpy ( & promise , begin , sizeof ( promiseid_t ) ) ;
if ( length > sizeof ( promiseid_t ) ) {
arg = Serialize : : load ( to , from , std : : vector < char > ( begin + sizeof ( promiseid_t ) , begin + length ) ) ;
}
else {
arg = v8 : : Undefined ( to - > _isolate ) ;
}
if ( static_cast < MessageType > ( packetType ) = = kResolvePromise ) {
to - > resolvePromise ( promise , arg ) ;
}
else {
to - > rejectPromise ( promise , arg ) ;
}
}
break ;
case kReleaseExport :
assert ( length = = sizeof ( exportid_t ) ) ;
exportid_t exportId ;
memcpy ( & exportId , begin , sizeof ( exportId ) ) ;
if ( to - > _exports [ exportId ] ) {
if ( to - > _exports [ exportId ] - > release ( ) ) {
to - > _exports . erase ( exportId ) ;
}
}
break ;
case kReleaseImport :
{
assert ( length = = sizeof ( exportid_t ) ) ;
exportid_t exportId ;
memcpy ( & exportId , begin , sizeof ( exportId ) ) ;
for ( size_t i = 0 ; i < to - > _imports . size ( ) ; + + i ) {
if ( to - > _imports [ i ] - > _task = = from - > getId ( ) & & to - > _imports [ i ] - > _export = = exportId ) {
to - > _imports [ i ] - > release ( ) ;
break ;
}
}
}
break ;
2016-04-16 21:30:52 +00:00
case kSetRequires :
2016-03-12 18:50:43 +00:00
{
2016-04-16 21:30:52 +00:00
v8 : : Handle < v8 : : Object > result = v8 : : Handle < v8 : : Object > : : Cast ( Serialize : : load ( to , from , std : : vector < char > ( begin , begin + length ) ) ) ;
to - > _sourceObject = v8 : : Persistent < v8 : : Object , v8 : : CopyablePersistentTraits < v8 : : Object > > ( to - > _isolate , result ) ;
2016-04-09 15:24:48 +00:00
}
break ;
2016-03-12 18:50:43 +00:00
case kActivate :
to - > activate ( ) ;
break ;
case kExecute :
{
assert ( length > = sizeof ( promiseid_t ) ) ;
promiseid_t promise ;
std : : memcpy ( & promise , begin , sizeof ( promiseid_t ) ) ;
v8 : : TryCatch tryCatch ( to - > _isolate ) ;
tryCatch . SetCaptureMessage ( true ) ;
tryCatch . SetVerbose ( true ) ;
2016-04-16 21:30:52 +00:00
v8 : : Handle < v8 : : Value > value = Serialize : : load ( to , from , std : : vector < char > ( begin + sizeof ( promiseid_t ) , begin + length ) ) ;
v8 : : Handle < v8 : : Object > object = v8 : : Handle < v8 : : Object > : : Cast ( value ) ;
v8 : : Handle < v8 : : String > source = v8 : : Handle < v8 : : String > : : Cast ( object - > Get ( v8 : : String : : NewFromUtf8 ( to - > _isolate , " source " ) ) ) ;
v8 : : Handle < v8 : : String > name = v8 : : Handle < v8 : : String > : : Cast ( object - > Get ( v8 : : String : : NewFromUtf8 ( to - > _isolate , " name " ) ) ) ;
to - > executeSource ( source , name ) ;
2016-03-12 18:50:43 +00:00
if ( tryCatch . HasCaught ( ) ) {
sendPromiseReject ( to , from , promise , Serialize : : store ( to , tryCatch ) ) ;
}
else {
sendPromiseResolve ( to , from , promise , v8 : : Undefined ( to - > _isolate ) ) ;
}
}
break ;
case kKill :
: : exit ( 1 ) ;
break ;
case kSetImports :
{
v8 : : Handle < v8 : : Object > result = v8 : : Handle < v8 : : Object > : : Cast ( Serialize : : load ( to , from , std : : vector < char > ( begin , begin + length ) ) ) ;
to - > _importObject = v8 : : Persistent < v8 : : Object , v8 : : CopyablePersistentTraits < v8 : : Object > > ( to - > _isolate , result ) ;
}
break ;
case kGetExports :
promiseid_t promise ;
assert ( length = = sizeof ( promise ) ) ;
std : : memcpy ( & promise , begin , sizeof ( promiseid_t ) ) ;
v8 : : Handle < v8 : : Object > result = v8 : : Local < v8 : : Object > : : New ( to - > _isolate , to - > _exportObject ) ;
sendPromiseResolve ( to , from , promise , result ) ;
break ;
}
}
void Task : : configureFromStdin ( ) {
_parent = TaskStub : : createParent ( this , STDIN_FILENO ) ;
}
std : : string Task : : resolveRequire ( const std : : string & require ) {
std : : string result ;
2016-04-09 15:24:48 +00:00
for ( size_t i = 0 ; i < _path . size ( ) ; + + i ) {
std : : string & path = _path [ i ] ;
2016-03-12 18:50:43 +00:00
std : : cout < < " Looking in " < < path < < " for " < < require < < " \n " ;
2016-04-09 18:36:43 +00:00
std : : string test ;
2016-03-12 18:50:43 +00:00
if ( require . find ( " .. " ) = = std : : string : : npos & & require . find ( ' / ' ) = = std : : string : : npos ) {
2016-04-09 18:36:43 +00:00
test = path + require ;
}
if ( test . size ( ) & & ( require . size ( ) < 3 | | require . rfind ( " .js " ) ! = require . size ( ) - 3 ) ) {
test + = " .js " ;
2016-03-12 18:50:43 +00:00
}
2016-04-09 18:36:43 +00:00
uv_fs_t request ;
if ( uv_fs_access ( _loop , & request , test . c_str ( ) , R_OK , 0 ) = = 0 ) {
result = test ;
break ;
2016-03-12 18:50:43 +00:00
}
}
return result ;
}
void Task : : require ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
v8 : : HandleScope scope ( args . GetIsolate ( ) ) ;
Task * task = Task : : get ( args . GetIsolate ( ) ) ;
v8 : : String : : Utf8Value pathValue ( args [ 0 ] ) ;
if ( * pathValue ) {
std : : string unresolved ( * pathValue , * pathValue + pathValue . length ( ) ) ;
std : : string path = task - > resolveRequire ( unresolved ) ;
if ( ! path . size ( ) ) {
args . GetReturnValue ( ) . Set ( args . GetIsolate ( ) - > ThrowException ( v8 : : Exception : : Error ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , ( " require(): Unable to resolve module: " + unresolved ) . c_str ( ) ) ) ) ) ;
} else {
ScriptExportMap : : iterator it = task - > _scriptExports . find ( path ) ;
if ( it ! = task - > _scriptExports . end ( ) ) {
v8 : : Handle < v8 : : Object > exports = v8 : : Local < v8 : : Object > : : New ( args . GetIsolate ( ) , it - > second ) ;
args . GetReturnValue ( ) . Set ( exports ) ;
} else {
v8 : : Handle < v8 : : Object > exports = v8 : : Object : : New ( args . GetIsolate ( ) ) ;
task - > _scriptExports [ path ] = v8 : : Persistent < v8 : : Object , v8 : : CopyablePersistentTraits < v8 : : Object > > ( args . GetIsolate ( ) , exports ) ;
v8 : : Handle < v8 : : String > name = v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , path . c_str ( ) ) ;
v8 : : Handle < v8 : : String > source = loadFile ( args . GetIsolate ( ) , path . c_str ( ) ) ;
std : : cout < < " Requiring script " < < path < < " \n " ;
if ( ! source . IsEmpty ( ) ) {
v8 : : Handle < v8 : : Object > global = args . GetIsolate ( ) - > GetCurrentContext ( ) - > Global ( ) ;
v8 : : Handle < v8 : : Value > oldExports = global - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " exports " ) ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " exports " ) , exports ) ;
v8 : : Handle < v8 : : Script > script = v8 : : Script : : Compile ( source , name ) ;
if ( ! script . IsEmpty ( ) ) {
script - > Run ( ) ;
std : : cout < < " Script " < < path < < " completed \n " ;
} else {
2016-04-18 19:58:09 +00:00
std : : cerr < < " Failed to compile " < < path < < " . \n " ;
2016-03-12 18:50:43 +00:00
}
global - > Set ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " exports " ) , oldExports ) ;
args . GetReturnValue ( ) . Set ( exports ) ;
} else {
std : : cerr < < " Failed to load " < < path < < " . \n " ;
}
}
}
} else {
args . GetReturnValue ( ) . Set ( args . GetIsolate ( ) - > ThrowException ( v8 : : Exception : : Error ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " require(): No module specified. " ) ) ) ) ;
}
}
2016-04-16 21:30:52 +00:00
v8 : : Handle < v8 : : Value > Task : : executeSource ( v8 : : Handle < v8 : : String > & source , v8 : : Handle < v8 : : String > & name ) {
v8 : : Isolate : : Scope isolateScope ( _isolate ) ;
v8 : : HandleScope handleScope ( _isolate ) ;
v8 : : Context : : Scope contextScope ( v8 : : Local < v8 : : Context > : : New ( _isolate , _context ) ) ;
v8 : : Handle < v8 : : Value > result ;
v8 : : String : : Utf8Value nameValue ( name ) ;
if ( ! source . IsEmpty ( ) ) {
v8 : : Handle < v8 : : Script > script = v8 : : Script : : Compile ( source , name ) ;
if ( ! script . IsEmpty ( ) ) {
script - > Run ( ) ;
} else {
2016-04-18 19:58:09 +00:00
std : : cerr < < " Failed to compile " < < * nameValue < < " . \n " ;
2016-04-16 21:30:52 +00:00
}
} else {
result = _isolate - > ThrowException ( v8 : : Exception : : Error ( v8 : : String : : NewFromUtf8 ( _isolate , ( std : : string ( " Failed to load " ) + * nameValue + " . " ) . c_str ( ) ) ) ) ;
}
return result ;
}
void Task : : childRequire ( const v8 : : FunctionCallbackInfo < v8 : : Value > & args ) {
v8 : : HandleScope scope ( args . GetIsolate ( ) ) ;
Task * task = Task : : get ( args . GetIsolate ( ) ) ;
v8 : : Handle < v8 : : Object > requiresObject = v8 : : Local < v8 : : Object > : : New ( args . GetIsolate ( ) , task - > _sourceObject ) ;
if ( ! requiresObject . IsEmpty ( ) ) {
v8 : : Handle < v8 : : String > name = args [ 0 ] - > ToString ( ) ;
v8 : : String : : Utf8Value nameValue ( name ) ;
ScriptExportMap : : iterator it = task - > _scriptExports . find ( * nameValue ) ;
if ( it ! = task - > _scriptExports . end ( ) ) {
v8 : : Handle < v8 : : Object > exports = v8 : : Local < v8 : : Object > : : New ( args . GetIsolate ( ) , it - > second ) ;
args . GetReturnValue ( ) . Set ( exports ) ;
} else {
v8 : : Handle < v8 : : Object > exports = v8 : : Object : : New ( args . GetIsolate ( ) ) ;
v8 : : Handle < v8 : : String > source = v8 : : Handle < v8 : : String > : : Cast ( requiresObject - > Get ( args [ 0 ] ) ) ;
if ( ! source . IsEmpty ( ) ) {
v8 : : Handle < v8 : : Object > global = args . GetIsolate ( ) - > GetCurrentContext ( ) - > Global ( ) ;
v8 : : Handle < v8 : : Value > oldExports = global - > Get ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " exports " ) ) ;
global - > Set ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " exports " ) , exports ) ;
v8 : : Handle < v8 : : Script > script = v8 : : Script : : Compile ( source , name ) ;
if ( ! script . IsEmpty ( ) ) {
script - > Run ( ) ;
} else {
2016-04-18 19:58:09 +00:00
std : : cerr < < " Failed to compile " < < * nameValue < < " . \n " ;
2016-04-16 21:30:52 +00:00
}
global - > Set ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , " exports " ) , oldExports ) ;
args . GetReturnValue ( ) . Set ( exports ) ;
} else {
args . GetReturnValue ( ) . Set ( args . GetIsolate ( ) - > ThrowException ( v8 : : Exception : : Error ( v8 : : String : : NewFromUtf8 ( args . GetIsolate ( ) , ( std : : string ( " Failed to load " ) + * nameValue + " . " ) . c_str ( ) ) ) ) ) ;
}
}
}
}