JSString* jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSExceptionState* exceptionState; JSCompartment* oldCompartment = NULL; jsval stringval; JS::RootedString string(cx); JS::RootedObject scopeObj(cx); if(jsdval->string) return jsdval->string; /* Reuse the string without copying or re-rooting it */ if(JSVAL_IS_STRING(jsdval->val)) { jsdval->string = JSVAL_TO_STRING(jsdval->val); return jsdval->string; } JS_BeginRequest(cx); /* Objects call JS_ValueToString in their own compartment. */ scopeObj = !JSVAL_IS_PRIMITIVE(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob; oldCompartment = JS_EnterCompartment(cx, scopeObj); exceptionState = JS_SaveExceptionState(cx); string = JS_ValueToString(cx, jsdval->val); JS_RestoreExceptionState(cx, exceptionState); JS_LeaveCompartment(cx, oldCompartment); oldCompartment = NULL; if(string) { stringval = STRING_TO_JSVAL(string); oldCompartment = JS_EnterCompartment(cx, jsdc->glob); } if(!string || !JS_WrapValue(cx, &stringval)) { if(oldCompartment) JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); return NULL; } jsdval->string = JSVAL_TO_STRING(stringval); if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString")) jsdval->string = NULL; JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); return jsdval->string; }
JSDValue* jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval) { JSCompartment* oldCompartment = NULL; JSContext* cx = jsdc->dumbContext; if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR))) { JS::RootedObject obj(cx); JS::RootedObject proto(cx); JS::RootedObject ctor(cx); JS_ASSERT(!jsdval->ctor); SET_BIT_FLAG(jsdval->flags, GOT_CTOR); if(JSVAL_IS_PRIMITIVE(jsdval->val)) return NULL; obj = JSVAL_TO_OBJECT(jsdval->val); if(!JS_GetPrototype(cx, obj, proto.address())) return NULL; if(!proto) return NULL; JS_BeginRequest(jsdc->dumbContext); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, obj); ctor = JS_GetConstructor(jsdc->dumbContext,proto); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(jsdc->dumbContext); if(!ctor) return NULL; jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor)); } if(jsdval->ctor) jsdval->ctor->nref++; return jsdval->ctor; }
void jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JSCompartment* oldCompartment = NULL; if(jsdval->string) { /* if the jsval is a string, then we didn't need to root the string */ if(!JSVAL_IS_STRING(jsdval->val)) { JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(cx, jsdc->glob); JS_RemoveStringRoot(cx, &jsdval->string); JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); } jsdval->string = NULL; } jsdval->funName = NULL; jsdval->className = NULL; DROP_CLEAR_VALUE(jsdc, jsdval->proto); DROP_CLEAR_VALUE(jsdc, jsdval->parent); DROP_CLEAR_VALUE(jsdc, jsdval->ctor); _freeProps(jsdc, jsdval); jsdval->flags = 0; }
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) : m_runtime(runtime), m_glob(runtime->m_rt), m_nativeScope(runtime->m_rt) { bool ok; m_cx = JS_NewContext(m_runtime->m_rt, STACK_CHUNK_SIZE); ENSURE(m_cx); JS_SetParallelIonCompilationEnabled(m_runtime->m_rt, true); // For GC debugging: // JS_SetGCZeal(m_cx, 2); JS_SetContextPrivate(m_cx, NULL); JS_SetErrorReporter(m_cx, ErrorReporter); JS_SetGlobalJitCompilerOption(m_runtime->m_rt, JSJITCOMPILER_ION_ENABLE, 1); JS_SetGlobalJitCompilerOption(m_runtime->m_rt, JSJITCOMPILER_BASELINE_ENABLE, 1); JS::ContextOptionsRef(m_cx).setExtraWarnings(1) .setWerror(0) .setVarObjFix(1) .setStrictMode(1); JS::CompartmentOptions opt; opt.setVersion(JSVERSION_LATEST); JSAutoRequest rq(m_cx); JS::RootedObject globalRootedVal(m_cx, JS_NewGlobalObject(m_cx, &global_class, NULL, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt)); m_comp = JS_EnterCompartment(m_cx, globalRootedVal); ok = JS_InitStandardClasses(m_cx, globalRootedVal); ENSURE(ok); m_glob = globalRootedVal.get(); // Use the testing functions to globally enable gcPreserveCode. This brings quite a // big performance improvement. In future SpiderMonkey versions, we should probably // use the functions implemented here: https://bugzilla.mozilla.org/show_bug.cgi?id=1068697 JS::RootedObject testingFunctionsObj(m_cx, js::GetTestingFunctions(m_cx)); ENSURE(testingFunctionsObj); JS::RootedValue ret(m_cx); JS_CallFunctionName(m_cx, testingFunctionsObj, "gcPreserveCode", JS::HandleValueArray::empty(), &ret); JS_DefineProperty(m_cx, m_glob, "global", globalRootedVal, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "print", ::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "log", ::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "warn", ::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "error", ::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "deepcopy", ::deepcopy, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); Register("ProfileStart", ::ProfileStart, 1); Register("ProfileStop", ::ProfileStop, 0); runtime->RegisterContext(m_cx); }
JSDScript* jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedValue val(cx, jsdval->val); JSFunction* fun = NULL; JSExceptionState* exceptionState; JS::RootedScript script(cx); JSDScript* jsdscript; JSCompartment* oldCompartment = NULL; if (!jsd_IsValueFunction(jsdc, jsdval)) return NULL; JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(cx, JSVAL_TO_OBJECT(val)); exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); if (fun) script = JS_GetFunctionScript(cx, fun); JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); if (!script) return NULL; JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, script); JSD_UNLOCK_SCRIPTS(jsdc); return jsdscript; }
JSString* jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedFunction fun(cx); JSExceptionState* exceptionState; JSCompartment* oldCompartment = NULL; if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval)) { JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val)); exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); if(!fun) return NULL; jsdval->funName = JS_GetFunctionId(fun); /* For compatibility we return "anonymous", not an empty string here. */ if (!jsdval->funName) jsdval->funName = JS_GetAnonymousString(jsdc->jsrt); } return jsdval->funName; }
static void gjstest_test_func_gjs_jsapi_util_string_js_string_utf8(void) { GjsUnitTestFixture fixture; JSContext *context; JSObject *global; const char *utf8_string = "\303\211\303\226 foobar \343\203\237"; char *utf8_result; jsval js_string; _gjs_unit_test_fixture_begin(&fixture); context = fixture.context; global = JS_GetGlobalObject(context); JSCompartment *oldCompartment = JS_EnterCompartment(context, global); g_assert(gjs_string_from_utf8(context, utf8_string, -1, &js_string) == JS_TRUE); g_assert(JSVAL_IS_STRING(js_string)); g_assert(gjs_string_to_utf8(context, js_string, &utf8_result) == JS_TRUE); JS_LeaveCompartment(context, oldCompartment); _gjs_unit_test_fixture_finish(&fixture); g_assert(g_str_equal(utf8_string, utf8_result)); g_free(utf8_result); }
JSBool jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedFunction fun(cx); JSExceptionState* exceptionState; JSCompartment* oldCompartment = NULL; if(jsd_IsValueFunction(jsdc, jsdval)) { JSBool ok = JS_FALSE; JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(cx, JSVAL_TO_OBJECT(jsdval->val)); exceptionState = JS_SaveExceptionState(cx); fun = JSD_GetValueFunction(jsdc, jsdval); JS_RestoreExceptionState(cx, exceptionState); if(fun) ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE; JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); JS_ASSERT(fun); return ok; } return !JSVAL_IS_PRIMITIVE(jsdval->val); }
JSDValue* jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval) { JSCompartment* oldCompartment = NULL; if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT))) { JSContext* cx = jsdc->dumbContext; JS::RootedObject obj(cx); JS::RootedObject parent(cx); JS_ASSERT(!jsdval->parent); SET_BIT_FLAG(jsdval->flags, GOT_PARENT); if(JSVAL_IS_PRIMITIVE(jsdval->val)) return NULL; obj = JSVAL_TO_OBJECT(jsdval->val); JS_BeginRequest(jsdc->dumbContext); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, obj); parent = JS_GetParentOrScopeChain(jsdc->dumbContext,obj); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(jsdc->dumbContext); if(!parent) return NULL; jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent)); } if(jsdval->parent) jsdval->parent->nref++; return jsdval->parent; }
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) : m_runtime(runtime), m_glob(runtime->m_rt), m_nativeScope(runtime->m_rt) { bool ok; m_cx = JS_NewContext(m_runtime->m_rt, STACK_CHUNK_SIZE); ENSURE(m_cx); JS_SetOffthreadIonCompilationEnabled(m_runtime->m_rt, true); // For GC debugging: // JS_SetGCZeal(m_cx, 2, JS_DEFAULT_ZEAL_FREQ); JS_SetContextPrivate(m_cx, NULL); JS_SetErrorReporter(m_runtime->m_rt, ErrorReporter); JS_SetGlobalJitCompilerOption(m_runtime->m_rt, JSJITCOMPILER_ION_ENABLE, 1); JS_SetGlobalJitCompilerOption(m_runtime->m_rt, JSJITCOMPILER_BASELINE_ENABLE, 1); JS::RuntimeOptionsRef(m_cx).setExtraWarnings(1) .setWerror(0) .setVarObjFix(1) .setStrictMode(1); JS::CompartmentOptions opt; opt.setVersion(JSVERSION_LATEST); // Keep JIT code during non-shrinking GCs. This brings a quite big performance improvement. opt.setPreserveJitCode(true); JSAutoRequest rq(m_cx); JS::RootedObject globalRootedVal(m_cx, JS_NewGlobalObject(m_cx, &global_class, NULL, JS::OnNewGlobalHookOption::FireOnNewGlobalHook, opt)); m_comp = JS_EnterCompartment(m_cx, globalRootedVal); ok = JS_InitStandardClasses(m_cx, globalRootedVal); ENSURE(ok); m_glob = globalRootedVal.get(); JS_DefineProperty(m_cx, m_glob, "global", globalRootedVal, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "print", ::print, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "log", ::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "warn", ::warn, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "error", ::error, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); JS_DefineFunction(m_cx, globalRootedVal, "deepcopy", ::deepcopy, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); Register("ProfileStart", ::ProfileStart, 1); Register("ProfileStop", ::ProfileStop, 0); Register("ProfileAttribute", ::ProfileAttribute, 1); runtime->RegisterContext(m_cx); }
bool JSAPITest::init() { rt = createRuntime(); if (!rt) return false; cx = createContext(); if (!cx) return false; JS_BeginRequest(cx); JS::RootedObject global(cx, createGlobal()); if (!global) return false; JS_EnterCompartment(cx, global); return true; }
/* * Retrieve a JSFunction* from a JSDValue*. This differs from * JS_ValueToFunction by fully unwrapping the object first. */ JSFunction* jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval) { JSObject *obj; JSFunction *fun; JSCompartment* oldCompartment = NULL; if (JSVAL_IS_PRIMITIVE(jsdval->val)) return NULL; obj = JS_UnwrapObject(JSVAL_TO_OBJECT(jsdval->val)); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, obj); fun = JS_ValueToFunction(jsdc->dumbContext, OBJECT_TO_JSVAL(obj)); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); return fun; }
const char* jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval) { jsval val = jsdval->val; JSCompartment* oldCompartment = NULL; if(!jsdval->className && !JSVAL_IS_PRIMITIVE(val)) { JSObject* obj = JSVAL_TO_OBJECT(val); JS_BeginRequest(jsdc->dumbContext); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, obj); jsdval->className = JS_GetDebugClassName(obj); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(jsdc->dumbContext); } return jsdval->className; }
bool JSAPITest::init() { rt = createRuntime(); if (!rt) return false; cx = createContext(); if (!cx) return false; #ifdef JS_GC_ZEAL JS_SetGCZeal(cx, 0, 0); #endif JS_BeginRequest(cx); js::RootedObject global(cx, createGlobal()); if (!global) return false; oldCompartment = JS_EnterCompartment(cx, global); return oldCompartment != NULL; }
/* * Retrieve a JSFunction* from a JSDValue*. This differs from * JS_ValueToFunction by fully unwrapping the object first. */ JSFunction* jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedObject obj(cx); JS::RootedFunction fun(cx); JSCompartment* oldCompartment = NULL; if (JSVAL_IS_PRIMITIVE(jsdval->val)) return NULL; obj = js::UncheckedUnwrap(JSVAL_TO_OBJECT(jsdval->val)); oldCompartment = JS_EnterCompartment(cx, obj); fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj)); JS_LeaveCompartment(cx, oldCompartment); return fun; }
static JSBool _buildProps(JSDContext* jsdc, JSDValue* jsdval) { JSContext* cx = jsdc->dumbContext; JS::RootedObject obj(cx); JSPropertyDescArray pda; unsigned i; JSCompartment* oldCompartment = NULL; JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props)); JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS))); JS_ASSERT(!JSVAL_IS_PRIMITIVE(jsdval->val)); if(JSVAL_IS_PRIMITIVE(jsdval->val)) return JS_FALSE; obj = JSVAL_TO_OBJECT(jsdval->val); JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, obj); if(!JS_GetPropertyDescArray(cx, obj, &pda)) { JS_EndRequest(cx); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); return JS_FALSE; } for(i = 0; i < pda.length; i++) { JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0); if(!prop) { _freeProps(jsdc, jsdval); break; } JS_APPEND_LINK(&prop->links, &jsdval->props); } JS_PutPropertyDescArray(cx, &pda); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(cx); SET_BIT_FLAG(jsdval->flags, GOT_PROPS); return !JS_CLIST_IS_EMPTY(&jsdval->props); }
void jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval) { JSCompartment* oldCompartment = NULL; JS_ASSERT(jsdval->nref > 0); if(0 == --jsdval->nref) { jsd_RefreshValue(jsdc, jsdval); if(JSVAL_IS_GCTHING(jsdval->val)) { JS_BeginRequest(jsdc->dumbContext); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, jsdc->glob); JS_RemoveValueRoot(jsdc->dumbContext, &jsdval->val); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(jsdc->dumbContext); } free(jsdval); } }
static void gjstest_test_func_gjs_jsapi_util_array(void) { GjsUnitTestFixture fixture; JSContext *context; JSObject *global; GjsRootedArray *array; int i; jsval value; _gjs_unit_test_fixture_begin(&fixture); context = fixture.context; array = gjs_rooted_array_new(); global = JS_GetGlobalObject(context); JSCompartment *oldCompartment = JS_EnterCompartment(context, global); for (i = 0; i < N_ELEMS; i++) { value = STRING_TO_JSVAL(JS_NewStringCopyZ(context, "abcdefghijk")); gjs_rooted_array_append(context, array, value); } JS_GC(JS_GetRuntime(context)); for (i = 0; i < N_ELEMS; i++) { char *ascii; value = gjs_rooted_array_get(context, array, i); g_assert(JSVAL_IS_STRING(value)); gjs_string_to_utf8(context, value, &ascii); g_assert(strcmp(ascii, "abcdefghijk") == 0); g_free(ascii); } gjs_rooted_array_free(context, array, TRUE); JS_LeaveCompartment(context, oldCompartment); _gjs_unit_test_fixture_finish(&fixture); }
/* * Create a new JSD value referring to a jsval. Copy string values into the * JSD compartment. Leave all other GCTHINGs in their native compartments * and access them through cross-compartment calls. */ JSDValue* jsd_NewValue(JSDContext* jsdc, jsval value) { JS::RootedValue val(jsdc->dumbContext, value); JSDValue* jsdval; JSCompartment* oldCompartment = NULL; if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue)))) return NULL; if(JSVAL_IS_GCTHING(val)) { JSBool ok; JS_BeginRequest(jsdc->dumbContext); oldCompartment = JS_EnterCompartment(jsdc->dumbContext, jsdc->glob); ok = JS_AddNamedValueRoot(jsdc->dumbContext, &jsdval->val, "JSDValue"); if(ok && JSVAL_IS_STRING(val)) { if(!JS_WrapValue(jsdc->dumbContext, val.address())) { ok = JS_FALSE; } } JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); JS_EndRequest(jsdc->dumbContext); if(!ok) { free(jsdval); return NULL; } } jsdval->val = val; jsdval->nref = 1; JS_INIT_CLIST(&jsdval->props); return jsdval; }
static void gjstest_test_func_gjs_jsapi_util_error_throw(void) { GjsUnitTestFixture fixture; JSContext *context; JSObject *global; jsval exc, value, previous; char *s = NULL; int strcmp_result; _gjs_unit_test_fixture_begin(&fixture); context = fixture.context; global = JS_GetGlobalObject(context); JSCompartment *oldCompartment = JS_EnterCompartment(context, global); /* Test that we can throw */ gjs_throw(context, "This is an exception %d", 42); g_assert(JS_IsExceptionPending(context)); exc = JSVAL_VOID; JS_GetPendingException(context, &exc); g_assert(!JSVAL_IS_VOID(exc)); value = JSVAL_VOID; JS_GetProperty(context, JSVAL_TO_OBJECT(exc), "message", &value); g_assert(JSVAL_IS_STRING(value)); gjs_string_to_utf8(context, value, &s); g_assert(s != NULL); strcmp_result = strcmp(s, "This is an exception 42"); free(s); if (strcmp_result != 0) g_error("Exception has wrong message '%s'", s); /* keep this around before we clear it */ previous = exc; JS_AddValueRoot(context, &previous); JS_ClearPendingException(context); g_assert(!JS_IsExceptionPending(context)); /* Check that we don't overwrite a pending exception */ JS_SetPendingException(context, previous); g_assert(JS_IsExceptionPending(context)); gjs_throw(context, "Second different exception %s", "foo"); g_assert(JS_IsExceptionPending(context)); exc = JSVAL_VOID; JS_GetPendingException(context, &exc); g_assert(!JSVAL_IS_VOID(exc)); g_assert(JSVAL_TO_OBJECT(exc) == JSVAL_TO_OBJECT(previous)); JS_RemoveValueRoot(context, &previous); JS_LeaveCompartment(context, oldCompartment); _gjs_unit_test_fixture_finish(&fixture); }
JSDProperty* jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr) { JSContext* cx = jsdc->dumbContext; JSDProperty* jsdprop; JSDProperty* iter = NULL; JS::RootedObject obj(cx); JS::RootedString name(cx, nameStr); unsigned attrs = 0; JSBool found; JSPropertyDesc pd; const jschar * nameChars; size_t nameLen; JS::RootedValue val(cx), nameval(cx); JS::RootedId nameid(cx); JSCompartment* oldCompartment = NULL; if(!jsd_IsValueObject(jsdc, jsdval)) return NULL; /* If we already have the prop, then return it */ while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter))) { JSString* propName = jsd_GetValueString(jsdc, jsdprop->name); if(propName) { int result; if (JS_CompareStrings(cx, propName, name, &result) && !result) return jsdprop; } JSD_DropProperty(jsdc, jsdprop); } /* Not found in property list, look it up explicitly */ if(!(obj = JSVAL_TO_OBJECT(jsdval->val))) return NULL; if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen))) return NULL; JS_BeginRequest(cx); oldCompartment = JS_EnterCompartment(cx, obj); JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found); if (!found) { JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); return NULL; } JS_ClearPendingException(cx); if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, val.address())) { if (JS_IsExceptionPending(cx)) { if (!JS_GetPendingException(cx, &pd.value)) { JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); return NULL; } pd.flags = JSPD_EXCEPTION; } else { pd.flags = JSPD_ERROR; pd.value = JSVAL_VOID; } } else { pd.value = val; } JS_LeaveCompartment(cx, oldCompartment); JS_EndRequest(cx); nameval = STRING_TO_JSVAL(name); if (!JS_ValueToId(cx, nameval, nameid.address()) || !JS_IdToValue(cx, nameid, &pd.id)) { return NULL; } pd.spare = 0; pd.alias = JSVAL_NULL; pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0 | (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0 | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0; return _newProperty(jsdc, &pd, JSDPD_HINTED); }
char* launchApp(char *appName,int isMenu){ static int nruns = 0; char* tmp = NULL,*script = NULL, *addrBack = NULL; if(appName){ static JSContext *cx = NULL; static JSObject *gl = NULL; script = fileToString(LIBRARY); if(!(cx = JS_NewContext(runtime, 8192))){ fprint(stderr,"Problem creating runtime\n"); exit(EXIT_FAILURE); } JS_SetErrorReporter(cx, reportError); //if(!(gl = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL))){ static struct JSPrincipals def_principles = {0}; if(!(gl = JS_NewGlobalObject(cx, &global_class, NULL))){ fprint(stderr,"Problem creating global object\n"); exit(EXIT_FAILURE); } JSCompartment *cmp = JS_EnterCompartment(cx, gl); if (!(JS_InitStandardClasses(cx, gl))){ fprint(stderr,"Problem creating standard classes\n"); exit(EXIT_FAILURE); } if(!JS_DefineFunctions(cx, gl, jsFunctions)){ fprint(stderr,"Unable to load native functions\n"); exit(EXIT_FAILURE); } globalObject = gl; char *pathToFile = NULL; if(isMenu){ pathToFile = (char*)malloc(1+strlen(MENU_DIR)); strcpy(pathToFile,MENU_DIR); } else { pathToFile = (char*)malloc(strlen(appName) + 1 + strlen(GAMES_DIR)); strcpy(pathToFile,GAMES_DIR); strcat(pathToFile,appName); //strcat(pathToFile,"/"); } JSBool ran = JS_FALSE; jsval retVal; obj.chrootPath = pathToFile; JS_SetPrivate(cx,gl,&obj); SDL_FlushEvents(); //clear queue of events before starting a new app. if(isMenu && 0 == nruns) { //define the property first_run = true; JS_DefineProperty(cx,JS_GetGlobalObject(cx),"first_run",BOOLEAN_TO_JSVAL(JS_TRUE),NULL,NULL,0); } if(script){ loadBaseClasses(appName,pathToFile,cx); //appName is without the extension, appPath needs the directory to chroot ran = JS_EvaluateScript(cx, gl, script, strlen(script) , LIBRARY,0, &retVal); } nruns++; clearModules(cx); JS_GC(JS_GetRuntime(cx)); JS_LeaveCompartment(cx,cmp); //The user requested to quit. if(SDL_QuitRequested()){ if(script)free(script); exitProgram(cx); exit(EXIT_SUCCESS); } if(isMenu && (ran == JS_FALSE)){ if(script) free(script); exitProgram(cx); exit(EXIT_FAILURE); } if(ran != JS_FALSE){ if(JSVAL_IS_STRING(retVal)){ addrBack = JS_EncodeString(cx,JSVAL_TO_STRING(retVal)); tmp = (char*)malloc(strlen(addrBack) +1); strcpy(tmp,addrBack); JS_free(cx,addrBack); addrBack = tmp; } if(JSVAL_IS_BOOLEAN(retVal) && isMenu){ if(script) free(script); if(pathToFile) free(pathToFile); exitProgram(cx); exit(EXIT_SUCCESS); } } else { addrBack = NULL; } if(script) free(script); if(pathToFile) free(pathToFile); JS_DestroyContext(cx); return addrBack; } }
static JSDContext* _newJSDContext(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user, JSObject* scopeobj) { JSDContext* jsdc = NULL; JSCompartment *oldCompartment = NULL; JSBool ok; if( ! jsrt ) return NULL; if( ! _validateUserCallbacks(callbacks) ) return NULL; jsdc = (JSDContext*) calloc(1, sizeof(JSDContext)); if( ! jsdc ) goto label_newJSDContext_failure; if( ! JSD_INIT_LOCKS(jsdc) ) goto label_newJSDContext_failure; JS_INIT_CLIST(&jsdc->links); jsdc->jsrt = jsrt; if( callbacks ) memcpy(&jsdc->userCallbacks, callbacks, callbacks->size); jsdc->user = user; #ifdef JSD_HAS_DANGEROUS_THREAD jsdc->dangerousThread = _dangerousThread; #endif JS_INIT_CLIST(&jsdc->threadsStates); JS_INIT_CLIST(&jsdc->sources); JS_INIT_CLIST(&jsdc->removedSources); jsdc->sourceAlterCount = 1; if( ! jsd_CreateAtomTable(jsdc) ) goto label_newJSDContext_failure; if( ! jsd_InitObjectManager(jsdc) ) goto label_newJSDContext_failure; if( ! jsd_InitScriptManager(jsdc) ) goto label_newJSDContext_failure; jsdc->dumbContext = JS_NewContext(jsdc->jsrt, 256); if( ! jsdc->dumbContext ) goto label_newJSDContext_failure; JS_BeginRequest(jsdc->dumbContext); JS_SetOptions(jsdc->dumbContext, JS_GetOptions(jsdc->dumbContext)); jsdc->glob = JS_NewGlobalObject(jsdc->dumbContext, &global_class, NULL); if( ! jsdc->glob ) goto label_newJSDContext_failure; oldCompartment = JS_EnterCompartment(jsdc->dumbContext, jsdc->glob); if ( ! JS_AddNamedObjectRoot(jsdc->dumbContext, &jsdc->glob, "JSD context global") ) goto label_newJSDContext_failure; ok = JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob); JS_LeaveCompartment(jsdc->dumbContext, oldCompartment); if( ! ok ) goto label_newJSDContext_failure; JS_EndRequest(jsdc->dumbContext); jsdc->data = NULL; jsdc->inited = JS_TRUE; JSD_LOCK(); JS_INSERT_LINK(&jsdc->links, &_jsd_context_list); JSD_UNLOCK(); return jsdc; label_newJSDContext_failure: if( jsdc ) { if ( jsdc->dumbContext && jsdc->glob ) JS_RemoveObjectRootRT(JS_GetRuntime(jsdc->dumbContext), &jsdc->glob); jsd_DestroyObjectManager(jsdc); jsd_DestroyAtomTable(jsdc); if( jsdc->dumbContext ) JS_EndRequest(jsdc->dumbContext); free(jsdc); } return NULL; }