/* * Tcl proc to embed Javascript */ int jsEval( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[] ){ v8log("TclBinding::jsEval (interp=%p)\n", interp); // Get handle to the V8 Isolate for this Tcl interpreter Isolate* isolate = v8::Isolate::GetCurrent(); assert(isolate != nullptr); // lock the Isolate for multi-threaded access (not reentrant on its own) Locker locker(isolate); // create a bindings map and store it in the current V8 Isolate TclVariableBindingsMap* varbindings = new TclVariableBindingsMap; isolate->SetData(0, varbindings); v8log("jsEval: created new bindings map at %lp\n", (void*)varbindings ); // validate input params if ( (objc != 3) ) { std::string msg("usage: jsEval [list of tcl vars to add to v8 context] { javascript }"); Tcl_SetObjResult(interp, Tcl_NewStringObj(msg.c_str(), msg.length())); return TCL_ERROR; } // get the argument list Tcl_Obj* arglist = objv[1]; if ( (arglist->typePtr == NULL) || strcmp(arglist->typePtr->name, "list") ) { std::string msg("jsEval: 1st arg not a list"); Tcl_SetObjResult(interp, Tcl_NewStringObj(msg.c_str(), msg.length())); return TCL_ERROR; } // get the JS snippet char* javascript = Tcl_GetString(objv[2]); if ( strlen(javascript) == 0 ) { std::string msg("jsEval: 2nd arg not a string"); Tcl_SetObjResult(interp, Tcl_NewStringObj(msg.c_str(), msg.length())); return TCL_ERROR; } // Create stack-allocated isolate and handle scopes. Isolate::Scope isolate_scope(isolate); HandleScope handle_scope(isolate); // new v8 global template Handle<ObjectTemplate> global_templ = ObjectTemplate::New(isolate); // scrum our F18 Interceptors global_templ->SetNamedPropertyHandler( &TclVariableBinding::GenericNamedPropertyReader, &TclVariableBinding::GenericNamedPropertyWriter ); // Create and Enter a new context for compiling and running the script. Handle<Context> context = Context::New(isolate, NULL, global_templ); context->Enter(); int arglistLength; Tcl_ListObjLength(interp, arglist, &arglistLength); v8log("arg list length == %d\n", arglistLength); for ( int i = 0; i < arglistLength; i++ ) { // get the variable NAME Tcl_Obj* varName; Tcl_ListObjIndex(interp, arglist, i, &varName); char* vn = Tcl_GetString(varName); v8log("binding %s (idx: %d) to V8\n", vn, i); // then create a binding and store it (*varbindings)[vn] = new TclVariableBinding(interp, varName); } // Compile v8log("compiling jsEval'ed script\n"); v8::MaybeLocal<v8::Script> jsSource = v8::Script::Compile(context, Nan::New<String>(javascript).ToLocalChecked()); if (jsSource.IsEmpty()) { v8log("*** jsSource.IsEmpty()\n"); } else { // Run v8log("running jsEval'ed script\n"); Nan::TryCatch tc; Nan::MaybeLocal<v8::Value> retv = jsSource.ToLocalChecked()->Run(); v8log("done running jsEval'ed script\n"); if ( tc.HasCaught() ) { // oops, exception raised from V8 while in JS land Local<Message> msg = tc.Message(); std::string msgtext(*String::Utf8Value(msg->Get())); v8log("*** caught JS exception: %s\n", msgtext.c_str()); } TclVariableBindingsMap::const_iterator it; for (it = varbindings->begin(); it != varbindings->end(); it++) { TclVariableBinding* vb = it->second; v8log("reverse mapping of %s (v8: %p) to Tcl...\n", it->first.c_str(), vb->m_v8val); Tcl_SetVar2Ex(vb->m_interp, it->first.c_str(), NULL, vb->m_tclvar, 0); delete vb; } varbindings->clear(); // handle return value, if there is one if (!retv.IsEmpty()) { Local<Value> rv = retv.ToLocalChecked(); std::string res(*String::Utf8Value(rv)); std::string restype(V8ValueType(rv)); v8log("Tcl_SetObjResult(interp == %lp, result == %s (%s)\n", (void*) interp, res.c_str(), restype.c_str()); Tcl_Obj* tclres = V8ToTcl(interp, rv); Tcl_SetObjResult(interp, tclres); } delete varbindings; } context->Exit(); // TODO: error handling! return TCL_OK; }
void* worker_routine(void *vdbc) { struct dbcontext * dbc = (struct dbcontext *) vdbc; //allocate array for objects that will be automatically removed after th_alloc_array(1000); // Socket to talk to dispatcher void *receiver = zmq_socket (dbc->context, ZMQ_REP); zmq_connect (receiver, "inproc://workers"); //Initialize our Isoloate Isolate *isolate = Isolate::New(); if(!isolate) { cout << "Failed to initialize Isolate, we can't work"; return 0; } Locker lock(isolate); Isolate::Scope isolateScope(isolate); HandleScope scope; Local<ObjectTemplate> globals = ObjectTemplate::New(); #define SETGLOB(name) globals->Set(String::New(""#name), FunctionTemplate::New(name)); globals->Set(String::New("addnum"), FunctionTemplate::New(addnum)); SETGLOB(print) globals->Set(String::New("put"), FunctionTemplate::New(put)); globals->Set(String::New("get"), FunctionTemplate::New(get)); globals->Set(String::New("del"), FunctionTemplate::New(del)); //iterator globals->Set(String::New("it_del"), FunctionTemplate::New(it_del)); globals->Set(String::New("it_new"), FunctionTemplate::New(it_new)); globals->Set(String::New("it_first"), FunctionTemplate::New(it_first)); globals->Set(String::New("it_last"), FunctionTemplate::New(it_last)); globals->Set(String::New("it_seek"), FunctionTemplate::New(it_seek)); globals->Set(String::New("it_next"), FunctionTemplate::New(it_next)); globals->Set(String::New("it_prev"), FunctionTemplate::New(it_prev)); globals->Set(String::New("it_valid"), FunctionTemplate::New(it_valid)); globals->Set(String::New("it_key"), FunctionTemplate::New(it_key)); globals->Set(String::New("it_val"), FunctionTemplate::New(it_val)); //BITSET SETGLOB(bs_new) SETGLOB(bs_reset) SETGLOB(bs_set) SETGLOB(bs_logicalor) SETGLOB(bs_logicalnot) SETGLOB(bs_inplace_logicalnot) SETGLOB(bs_logicaland) SETGLOB(bs_sparselogicaland) SETGLOB(bs_tostring) SETGLOB(bs_makeSameSize) SETGLOB(bs_eq) SETGLOB(putbs) SETGLOB(getbs) SETGLOB(bs_it_new) SETGLOB(bs_it_end) SETGLOB(bs_it_isend) SETGLOB(bs_it_next) SETGLOB(bs_it_val) SETGLOB(bs_it_end) SETGLOB(bs_it_eq) Handle<Context> context = Context::New(NULL, globals); context->Enter(); //Running init script with library functions if (dbc->init_code != NULL) { TryCatch try_catch; Local<String> source = String::New(dbc->init_code); Local<Script> script = Script::Compile(source); if(script.IsEmpty()) { ReportException(&try_catch); } else { // Run the function once and catch the error to generate machine code Local<Value> result = script->Run(); } } while (1) { zmq_msg_t req; int rc = zmq_msg_init (&req); assert (rc == 0); rc = zmq_recv (receiver, &req, 0); assert (rc == 0); zmq_msg_t reply; //rc = zmq_msg_init_size (&reply, 200); //assert (rc == 0); //test mq speed only #if 0 rc = zmq_msg_init_size (&reply, 200); assert (rc == 0); rc = zmq_msg_copy (&reply, &req); assert (rc == 0); rc = zmq_send (receiver, &reply, 0); assert (rc == 0); //s_sleep(1); zmq_msg_close (&req); zmq_msg_close (&reply); continue; #endif //std::cout << "thread: " << pthread_self() << " Received script: " << (char*) zmq_msg_data(&req) << std::endl; //leveldb::Status s; #if 1 Context::Scope contextScope(context); // Compile a function which will keep using the stack until v8 cuts it off //Local<Script> script = Local<Script>::New(Script::Compile(String::New( (char*) zmq_msg_data(&req) ))); TryCatch try_catch; Local<String> source = String::New((char*) zmq_msg_data(&req)); Local<Script> script = Script::Compile(source); if(script.IsEmpty()) { ReportException(&try_catch); String::Utf8Value error(try_catch.Exception()); v8::Handle<v8::Message> message = try_catch.Message(); int line_num = 0; int col_num = 0; if (message.IsEmpty()) { }else { line_num = message->GetLineNumber(); col_num = message->GetStartColumn(); } int mess_size = error.length()+100; rc = zmq_msg_init_size (&reply, mess_size); assert (rc == 0); //cerr << "compile error line: " << " message: " << *error << endl; snprintf ((char*) zmq_msg_data (&reply), mess_size, "2; {res: 'COMPILE ERROR', line: %d, col: %d, message: '%s'}", line_num, col_num, *error); } else { // Run the function once and catch the error to generate machine code Local<Value> result = script->Run(); if (try_catch.HasCaught()) { //TODO: escape string String::Utf8Value message(try_catch.Exception()); int mess_size = message.length()+100; rc = zmq_msg_init_size (&reply, mess_size); assert (rc == 0); std::cout <<"exception->" <<*message <<"\n"; snprintf ((char*) zmq_msg_data (&reply), mess_size, "1; {res: 'ERROR', message: '%s'}", *message); } else { //TODO: escape string String::Utf8Value message(result->ToString()); int mess_size = message.length()+2; rc = zmq_msg_init_size (&reply, mess_size); assert (rc == 0); snprintf ((char*) zmq_msg_data (&reply), mess_size, " %s", *message); } } #endif /* Send the message to the socket */ rc = zmq_send (receiver, &reply, 0); assert (rc == 0); //s_sleep(1); zmq_msg_close (&req); zmq_msg_close (&reply); free_objects(); } context->Exit(); //printf("Iter: %d , Result: %ld ; from thread: %ld \n", i, res, tid); //context.Dispose(); //script.Dispose(); Unlocker unlock(isolate); //isolate->Exit(); //isolate->Dispose(); zmq_close (receiver); return NULL; }
void c_contextExit(Handle<Context> context) { context->Exit(); }