/* less bloat but this only works with 4 byte argv values */ bool ControllerListener::call(const char *funcname, int argc, jsval *argv) { jsval fval = JSVAL_VOID; jsval ret = JSVAL_VOID; JSBool res; func("calling js %s.%s()", name, funcname); JS_SetContextThread(jsContext); JS_BeginRequest(jsContext); res = JS_GetProperty(jsContext, jsObject, funcname, &fval); if(!res || JSVAL_IS_VOID(fval)) { // using func() instead of error() because this is not a real error condition. // controller could ask for unregistered functions ... // for instance in the case of a keyboardcontroller which propagates keystrokes // for unregistered keys func("method %s not found in %s controller", funcname, name); JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); return(false); } res = JS_CallFunctionValue(jsContext, jsObject, fval, argc, argv, &ret); JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); if(res == JS_FALSE) { error("%s : failed call", __PRETTY_FUNCTION__); return(false); } return(true); }
bool ControllerListener::frame() { jsval ret = JSVAL_VOID; JSBool res; JS_SetContextThread(jsContext); JS_BeginRequest(jsContext); if (!frameFunc) { res = JS_GetProperty(jsContext, jsObject, "frame", &frameFunc); if(!res || JSVAL_IS_VOID(frameFunc)) { error("method frame not found in TriggerController"); JS_ClearContextThread(jsContext); JS_EndRequest(jsContext); return false; } } res = JS_CallFunctionValue(jsContext, jsObject, frameFunc, 0, NULL, &ret); JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); if (res == JS_FALSE) { error("trigger call frame() failed, deactivate ctrl"); //active = false; return false; } return true; }
int JsParser::parse(const char *command) { func("%u:%s:%s",__LINE__,__FILE__,__FUNCTION__); int eval_res; jsval res; JSString *str; if(!command) { /* true paranoia */ warning("NULL command passed to javascript parser"); return 0; } func("JS parse: %s", command); JsExecutionContext *new_script = new JsExecutionContext(this); JS_SetContextThread(new_script->cx); JS_BeginRequest(new_script->cx); eval_res = evaluate(new_script->cx, new_script->obj, (const char*)"parsed command", command, strlen(command)); JS_EndRequest(new_script->cx); JS_ClearContextThread(new_script->cx); if (eval_res) runtimes.append(new_script); else delete new_script; func("JS parse result: %i", eval_res); return eval_res; }
void *StartThreadSpidermonkey(void *pData) {// begin StartThreadSpidermonkey pthread_mutex_lock(&g_pSpiderMonkeyMutex); /* The following mailling list post describes how to CORRECTLY use the threading API support with Spidermonkey "Thread from SpiderMonkey newsgroup" http://archive.gingerall.cz/archives/public/sablot2004/msg00117.html */ // Notify the Spidermonkey that we'll be processing in a thread #ifdef ADM_JS_THREADSAFE JS_SetContextThread(g_pCx); JS_BeginRequest(g_pCx); #endif bool ret = false; const char *pScriptFile = static_cast<const char *>(pData); ret = parseECMAScript(pScriptFile); if(ret == false) { if( actual_workbench_file ) ADM_dealloc(actual_workbench_file); actual_workbench_file = ADM_strdup(pScriptFile); } // Notify Spidermonkey that our thread processing has finished #ifdef ADM_JS_THREADSAFE JS_EndRequest(g_pCx); JS_ClearContextThread(g_pCx); #endif pthread_mutex_unlock(&g_pSpiderMonkeyMutex); return NULL; }// end StartThreadSpidermonkey
JsExecutionContext::~JsExecutionContext() { JS_SetContextThread(cx); JS_GC(cx); JS_BeginRequest(cx); JS_ClearScope(cx, obj); JS_EndRequest(cx); JS_ClearContextThread(cx); JS_DestroyContext(cx); JS_DestroyRuntime(rt); }
bool __fastcall GameEventCallback(Script* script, void* argv, uint argc) { if(script->IsRunning() && script->IsListenerRegistered("gamemsg")) { AutoRoot** argv = new AutoRoot*[1]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), (char*)argv))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("gamemsg", 1, argv); } return true; }
/* JSCall function by name, cvalues will be converted * * deactivates controller if any script errors! * * format values: * case 'b': BOOLEAN_TO_JSVAL((JSBool) va_arg(ap, int)); * case 'c': INT_TO_JSVAL((uint16) va_arg(ap, unsigned int)); * case 'i': * case 'j': js_NewNumberValue(cx, (jsdouble) va_arg(ap, int32), sp) * case 'u': js_NewNumberValue(cx, (jsdouble) va_arg(ap, uint32), sp) * case 'd': * case 'I': js_NewDoubleValue(cx, va_arg(ap, jsdouble), sp) * case 's': JS_NewStringCopyZ(cx, va_arg(ap, char *)) * case 'W': JS_NewUCStringCopyZ(cx, va_arg(ap, jschar *)) * case 'S': va_arg(ap, JSString *) * case 'o': OBJECT_TO_JSVAL(va_arg(ap, JSObject *) * case 'f': * fun = va_arg(ap, JSFunction *); * fun ? OBJECT_TO_JSVAL(fun->object) : JSVAL_NULL; * case 'v': va_arg(ap, jsval); */ bool ControllerListener::call(const char *funcname, int argc, const char *format, ...) { va_list ap; jsval fval = JSVAL_VOID; jsval ret = JSVAL_VOID; func("%s try calling method %s.%s(argc:%i)", __func__, name, funcname, argc); JS_SetContextThread(jsContext); JS_BeginRequest(jsContext); int res = JS_GetProperty(jsContext, jsObject, funcname, &fval); if(JSVAL_IS_VOID(fval)) { warning("method unresolved by JS_GetProperty"); } else { jsval *argv; void *markp; va_start(ap, format); argv = JS_PushArgumentsVA(jsContext, &markp, format, ap); va_end(ap); res = JS_CallFunctionValue(jsContext, jsObject, fval, argc, argv, &ret); JS_PopArguments(jsContext, &markp); if (res) { if(!JSVAL_IS_VOID(ret)) { JSBool ok; JS_ValueToBoolean(jsContext, ret, &ok); if (ok) // JSfunc returned 'true', so event is done { JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); return true; } } } } JS_EndRequest(jsContext); JS_ClearContextThread(jsContext); return false; // no callback, redo on next controller }
bool __fastcall ChatEventCallback(Script* script, void* argv, uint argc) { ChatEventHelper* helper = (ChatEventHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered(helper->event)) { AutoRoot** argv = new AutoRoot*[2]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->nick))); argv[1] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->msg))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync(helper->event, 2, argv); } return true; }
bool __fastcall CopyDataCallback(Script* script, void* argv, uint argc) { CopyDataHelper* helper = (CopyDataHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered("copydata")) { AutoRoot** argv = new AutoRoot*[2]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->mode, argv[0]->value()); argv[1] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->msg))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("copydata", 2, argv); } return true; }
JsExecutionContext::JsExecutionContext(JsParser *jsParser) { parser = jsParser; /* Create a new runtime environment. */ rt = JS_NewRuntime(8L * 1024L * 1024L); if (!rt) { error("JsParser :: error creating runtime"); return; /* XXX should return int or ptr! */ } /* Create a new context. */ cx = JS_NewContext(rt, STACK_CHUNK_SIZE); /* if global_context does not have a value, end the program here */ if (cx == NULL) { error("JsParser :: error creating context"); return; } JS_BeginRequest(cx); // Store a reference to ourselves in the context ... JS_SetContextPrivate(cx, parser); /* Set a more strict error checking */ JS_SetOptions(cx, JSOPTION_VAROBJFIX); // | JSOPTION_STRICT); /* Set the branch callback */ #if defined JSOPTION_NATIVE_BRANCH_CALLBACK JS_SetBranchCallback(cx, js_static_branch_callback); #else JS_SetOperationCallback(cx, js_static_branch_callback); #endif /* Set the error reporter */ JS_SetErrorReporter(cx, js_error_reporter); /* Create the global object here */ // JS_SetGlobalObject(global_context, global_object); // this is done in init_class / JS_InitStandardClasses. obj = JS_NewObject(cx, &global_class, NULL, NULL); init_class(); JS_EndRequest(cx); // deassociate this context from the creating thread // so that it can be used in other threads // https://developer.mozilla.org/en/SpiderMonkey/JSAPI_Reference/JS_NewContext JS_ClearContextThread(cx); /** register SIGINT signal */ // signal(SIGINT, js_sigint_handler); }
/* return lines read, or 0 on error */ int JsParser::open(const char* script_file) { JsExecutionContext *new_script = new JsExecutionContext(this); JS_SetContextThread(new_script->cx); JS_BeginRequest(new_script->cx); int ret = open(new_script->cx, new_script->obj, script_file); JS_EndRequest(new_script->cx); JS_ClearContextThread(new_script->cx); if (ret) { new_script->set_name(script_file); runtimes.append(new_script); } else { delete new_script; } return ret; }
void SG_jscontext__release(SG_context * pCtx, SG_jscontext ** ppJs) { if(ppJs==NULL || *ppJs==NULL) return; if(gpJSContextPoolGlobalState->ssjsMutable) { SG_httprequestprofiler__start(SG_HTTPREQUESTPROFILER_CATEGORY__JSREQUEST_TOGGLING); JS_EndRequest((*ppJs)->cx); JS_DestroyContext((*ppJs)->cx); SG_httprequestprofiler__stop(); if(SG_context__has_err(pCtx)) // An error was produced during GC... { SG_log__report_error__current_error(pCtx); SG_context__err_reset(pCtx); } SG_NULLFREE(pCtx, (*ppJs)); } else { SG_jscontext * pJs = *ppJs; JS_MaybeGC(pJs->cx); JS_SetContextPrivate(pJs->cx, NULL); // Clear out the old pCtx pointer. SG_httprequestprofiler__start(SG_HTTPREQUESTPROFILER_CATEGORY__JSREQUEST_TOGGLING); JS_EndRequest(pJs->cx); pJs->isInARequest = SG_FALSE; (void)JS_ClearContextThread(pJs->cx); SG_httprequestprofiler__stop(); SG_ERR_CHECK_RETURN( SG_mutex__lock(pCtx, &gpJSContextPoolGlobalState->lock) ); pJs->pNextAvailableContext = gpJSContextPoolGlobalState->pFirstAvailableContext; gpJSContextPoolGlobalState->pFirstAvailableContext = pJs; --gpJSContextPoolGlobalState->numContextsCheckedOut; SG_ERR_CHECK_RETURN( SG_mutex__unlock(pCtx, &gpJSContextPoolGlobalState->lock) ); *ppJs = NULL; } }
bool __fastcall ItemEventCallback(Script* script, void* argv, uint argc) { ItemEventHelper* helper = (ItemEventHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered("itemaction")) { AutoRoot** argv = new AutoRoot*[4]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(); argv[1] = new AutoRoot(); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->id, argv[0]->value()); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->mode, argv[1]->value()); argv[2] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->code))); argv[3] = new AutoRoot(BOOLEAN_TO_JSVAL(helper->global)); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("itemaction", 4, argv); } return true; }
void Engine::cleanup() { while ( !m_contexts.empty() ) { JSContext *cx = m_contexts.top(); m_contexts.pop(); JS_ClearContextThread(cx); JS_DestroyContext(cx); } if ( m_runtime!=NULL ) { JS_DestroyRuntime(m_runtime); m_runtime = NULL; } JS_ShutDown(); }
bool __fastcall GameActionEventCallback(Script* script, void* argv, uint argc) { GameActionEventHelper* helper = (GameActionEventHelper*)argv; if(script->IsRunning() && script->IsListenerRegistered("gameevent")) { AutoRoot** argv = new AutoRoot*[5]; JS_SetContextThread(ScriptEngine::GetGlobalContext()); argv[0] = new AutoRoot(); argv[1] = new AutoRoot(); argv[2] = new AutoRoot(); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->mode, argv[0]->value()); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->param1, argv[1]->value()); JS_NewNumberValue(ScriptEngine::GetGlobalContext(), helper->param2, argv[2]->value()); argv[3] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->name1))); argv[4] = new AutoRoot(STRING_TO_JSVAL(JS_NewStringCopyZ(ScriptEngine::GetGlobalContext(), helper->name2))); JS_ClearContextThread(ScriptEngine::GetGlobalContext()); script->ExecEventAsync("gameevent", 5, argv); } return true; }
int Controller::JSCall(const char *funcname, int argc, const char *format, ...) { int res; jsval *argv; va_list args; ControllerListener *listener = listeners.begin(); va_start(args, format); va_end(args); while (listener) { void *markp = NULL; JS_SetContextThread(listener->context()); JS_BeginRequest(listener->context()); argv = JS_PushArgumentsVA(listener->context(), &markp, format, args); JS_EndRequest(listener->context()); JS_ClearContextThread(listener->context()); // TODO - unregister listener if returns false if (listener->call(funcname, argc, argv)) res++; listener = (ControllerListener *)listener->next; } return res; }
static int js_init(void) { JSContext *cx; jsval val; JS_SetCStringsAreUTF8(); runtime = JS_NewRuntime(0x1000000); cx = js_newctx(err_reporter); JS_BeginRequest(cx); showtimeobj = JS_NewObject(cx, &showtime_class, NULL, NULL); JS_DefineFunctions(cx, showtimeobj, showtime_functions); val = INT_TO_JSVAL(showtime_get_version_int()); JS_SetProperty(cx, showtimeobj, "currentVersionInt", &val); val = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, htsversion)); JS_SetProperty(cx, showtimeobj, "currentVersionString", &val); JSFunction *fn = JS_DefineFunction(cx, showtimeobj, "RichText", js_RichText, 1, 0); RichText = JS_GetFunctionObject(fn); JS_AddNamedRoot(cx, &showtimeobj, "showtime"); js_global_cx = cx; JS_EndRequest(cx); JS_ClearContextThread(cx); js_global_pc = prop_courier_create_lockmgr("js", js_lockmgr, cx, js_global_pc_prologue, js_global_pc_epilogue); return 0; }
inline void end_request(spidermonkey_vm *vm) { JS_EndRequest(vm->context); JS_ClearContextThread(vm->context); }
bool Engine::executeFile(FILE *file,HttpServerRequest &httpRequest,HttpServerResponse &httpResponse) { JSContext *cx = NULL; JSObject *obj = NULL; m_mutex.acquire_write(); // pop any available context if ( !m_contexts.empty() ) { cx = m_contexts.top(); m_contexts.pop(); } m_mutex.release(); if ( cx==NULL ) { // create new context cx = JS_NewContext(m_runtime,8192); if ( cx==NULL ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not create context. Engine is unavailable."); return false; } JS_SetErrorReporter(cx,reportError); if ( LogManager::getInstance()->isDebug() ) { LogManager::getInstance()->debug(LOGGER_CLASSNAME,"Created new context"); } } bool result = false; // begin request (requires js_threadsafe compilation) JS_SetContextThread(cx); JS_BeginRequest(cx); // create global object obj = JS_NewObject(cx,&globalClass,0,0); if ( obj==NULL ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not create global object"); } else { // initialize standard classes on global object if ( JS_InitStandardClasses(cx,obj)==JS_FALSE ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not init standard classes"); } else { // initialize custom classes on global object if ( !initCustomClasses(cx,obj) ) { LogManager::getInstance()->warning(LOGGER_CLASSNAME,"Could not init custom classes"); } else { // create predefined objects on global object createPredefinedObjects(cx,obj,httpRequest); // create context private ContextPrivate *cxPrivate = new ContextPrivate(this,httpRequest,httpResponse); JS_SetContextPrivate(cx,cxPrivate); // execute script in the context result = executeFile(file,cx,obj); // cleanup predefined objects on context object // note: this one might not be needed, remove later if ok cleanupPredefinedObjects(cx,obj); delete cxPrivate; } } } JS_GC(cx); // force garbage collection // end request (requires js_threadsafe) JS_EndRequest(cx); JS_ClearContextThread(cx); // return context to js engine m_mutex.acquire_write(); m_contexts.push(cx); m_mutex.release(); return result; }
void JsExecutionContext::gc() { JS_SetContextThread(cx); JS_MaybeGC(cx); JS_ClearContextThread(cx); }
static void js_global_pc_epilogue(void) { JS_ClearContextThread(js_global_cx); }