static JSBool math_random(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSRuntime *rt; jsdouble z; rt = cx->runtime; JS_LOCK_RUNTIME(rt); random_init(rt); z = random_nextDouble(rt); JS_UNLOCK_RUNTIME(rt); return js_NewNumberValue(cx, z, rval); }
JSContext * js_ContextIterator(JSRuntime *rt, JSContext **iterp) { JSContext *cx = *iterp; JS_LOCK_RUNTIME(rt); if (!cx) cx = (JSContext *)&rt->contextList; cx = (JSContext *)cx->links.next; if (&cx->links == &rt->contextList) cx = NULL; *iterp = cx; JS_UNLOCK_RUNTIME(rt); return cx; }
JSContext * js_NewContext(JSRuntime *rt, size_t stackChunkSize) { JSContext *cx; JSBool ok, first; cx = (JSContext *) malloc(sizeof *cx); if (!cx) return NULL; memset(cx, 0, sizeof *cx); cx->runtime = rt; #ifdef JS_THREADSAFE js_InitContextForLocking(cx); #endif JS_LOCK_RUNTIME(rt); for (;;) { first = (rt->contextList.next == &rt->contextList); if (rt->state == JSRTS_UP) { JS_ASSERT(!first); break; } if (rt->state == JSRTS_DOWN) { JS_ASSERT(first); rt->state = JSRTS_LAUNCHING; break; } JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT); } JS_APPEND_LINK(&cx->links, &rt->contextList); JS_UNLOCK_RUNTIME(rt); /* * First we do the infallible, every-time per-context initializations. * Should a later, fallible initialization (js_InitRegExpStatics, e.g., * or the stuff under 'if (first)' below) fail, at least the version * and arena-pools will be valid and safe to use (say, from the last GC * done by js_DestroyContext). */ cx->version = JSVERSION_DEFAULT; cx->jsop_eq = JSOP_EQ; cx->jsop_ne = JSOP_NE; JS_InitArenaPool(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval)); JS_InitArenaPool(&cx->codePool, "code", 1024, sizeof(jsbytecode)); JS_InitArenaPool(&cx->notePool, "note", 1024, sizeof(jssrcnote)); JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble)); #if JS_HAS_REGEXPS if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) { js_DestroyContext(cx, JS_NO_GC); return NULL; } #endif #if JS_HAS_EXCEPTIONS cx->throwing = JS_FALSE; #endif /* * If cx is the first context on this runtime, initialize well-known atoms, * keywords, numbers, and strings. If one of these steps should fail, the * runtime will be left in a partially initialized state, with zeroes and * nulls stored in the default-initialized remainder of the struct. We'll * clean the runtime up under js_DestroyContext, because cx will be "last" * as well as "first". */ if (first) { ok = (rt->atomState.liveAtoms == 0) ? js_InitAtomState(cx, &rt->atomState) : js_InitPinnedAtoms(cx, &rt->atomState); if (ok) ok = js_InitScanner(cx); if (ok) ok = js_InitRuntimeNumberState(cx); if (ok) ok = js_InitRuntimeStringState(cx); if (!ok) { js_DestroyContext(cx, JS_NO_GC); return NULL; } JS_LOCK_RUNTIME(rt); rt->state = JSRTS_UP; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_RUNTIME(rt); } return cx; }
void js_DestroyContext(JSContext *cx, JSGCMode gcmode) { JSRuntime *rt; JSBool last; JSArgumentFormatMap *map; rt = cx->runtime; /* Remove cx from context list first. */ JS_LOCK_RUNTIME(rt); JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING); JS_REMOVE_LINK(&cx->links); last = (rt->contextList.next == &rt->contextList); if (last) rt->state = JSRTS_LANDING; JS_UNLOCK_RUNTIME(rt); if (last) { /* Unpin all pinned atoms before final GC. */ js_UnpinPinnedAtoms(&rt->atomState); /* Unlock and clear GC things held by runtime pointers. */ js_FinishRuntimeNumberState(cx); js_FinishRuntimeStringState(cx); /* Clear debugging state to remove GC roots. */ JS_ClearAllTraps(cx); JS_ClearAllWatchPoints(cx); } #if JS_HAS_REGEXPS /* * Remove more GC roots in regExpStatics, then collect garbage. * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within * XXX this function call to wait for any racing GC to complete, in the * XXX case where JS_DestroyContext is called outside of a request on cx */ js_FreeRegExpStatics(cx, &cx->regExpStatics); #endif #ifdef JS_THREADSAFE /* * Destroying a context implicitly calls JS_EndRequest(). Also, we must * end our request here in case we are "last" -- in that event, another * js_DestroyContext that was not last might be waiting in the GC for our * request to end. We'll let it run below, just before we do the truly * final GC and then free atom state. * * At this point, cx must be inaccessible to other threads. It's off the * rt->contextList, and it should not be reachable via any object private * data structure. */ while (cx->requestDepth != 0) JS_EndRequest(cx); #endif if (last) { /* Always force, so we wait for any racing GC to finish. */ js_ForceGC(cx); /* Iterate until no finalizer removes a GC root or lock. */ while (rt->gcPoke) js_GC(cx, GC_LAST_CONTEXT); /* Try to free atom state, now that no unrooted scripts survive. */ if (rt->atomState.liveAtoms == 0) js_FreeAtomState(cx, &rt->atomState); /* Take the runtime down, now that it has no contexts or atoms. */ JS_LOCK_RUNTIME(rt); rt->state = JSRTS_DOWN; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); JS_UNLOCK_RUNTIME(rt); } else { if (gcmode == JS_FORCE_GC) js_ForceGC(cx); else if (gcmode == JS_MAYBE_GC) JS_MaybeGC(cx); } /* Free the stuff hanging off of cx. */ JS_FinishArenaPool(&cx->stackPool); JS_FinishArenaPool(&cx->codePool); JS_FinishArenaPool(&cx->notePool); JS_FinishArenaPool(&cx->tempPool); if (cx->lastMessage) free(cx->lastMessage); /* Remove any argument formatters. */ map = cx->argumentFormatMap; while (map) { JSArgumentFormatMap *temp = map; map = map->next; JS_free(cx, temp); } /* Destroy the resolve recursion damper. */ if (cx->resolvingTable) { JS_DHashTableDestroy(cx->resolvingTable); cx->resolvingTable = NULL; } /* Finally, free cx itself. */ free(cx); }
static JSBool obj_watch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSFunction *fun; jsval userid, symid, propid, value; JSAtom *atom; JSRuntime *rt; JSBool ok; JSProperty *prop; JSPropertyOp getter, setter; JSClass *clasp; fun = JS_ValueToFunction(cx, argv[1]); if (!fun) return JS_FALSE; argv[1] = OBJECT_TO_JSVAL(fun->object); /* * Lock the world while we look in obj. Be sure to return via goto out * on error, so we unlock. */ rt = cx->runtime; JS_LOCK_RUNTIME(rt); /* Compute the unique int/atom symbol id needed by js_LookupProperty. */ userid = argv[0]; if (JSVAL_IS_INT(userid)) { symid = userid; atom = NULL; } else { atom = js_ValueToStringAtom(cx, userid); if (!atom) { ok = JS_FALSE; goto out; } symid = (jsval)atom; } ok = js_LookupProperty(cx, obj, symid, &obj, &prop); if (atom) js_DropAtom(cx, atom); if (!ok) goto out; /* Set propid from the property, in case it has a tinyid. */ if (prop) { propid = prop->id; getter = prop->getter; setter = prop->setter; value = prop->object->slots[prop->slot]; } else { propid = userid; clasp = obj->map->clasp; getter = clasp->getProperty; setter = clasp->setProperty; value = JSVAL_VOID; } /* * Security policy is implemented in getters and setters, so we have to * call get and set here to let the JS API client check for a watchpoint * that crosses a trust boundary. * XXX assumes get and set are idempotent, should use a clasp->watch hook */ ok = getter(cx, obj, propid, &value) && setter(cx, obj, propid, &value); if (!ok) goto out; /* Finally, call into jsdbgapi.c to set the watchpoint on userid. */ ok = JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, fun->object); out: JS_UNLOCK_RUNTIME(rt); return ok; }